removed unused net_vcr (and all other traces of vcr system), apparently a predecessor...
[xonotic/darkplaces.git] / net_main.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
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.
8
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.  
12
13 See the GNU General Public License for more details.
14
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.
18
19 */
20 // net_main.c
21
22 #include "quakedef.h"
23
24 qsocket_t       *net_activeSockets = NULL;
25 qsocket_t       *net_freeSockets = NULL;
26 int                     net_numsockets = 0;
27
28 qboolean        serialAvailable = false;
29 qboolean        ipxAvailable = false;
30 qboolean        tcpipAvailable = false;
31
32 int                     net_hostport;
33 int                     DEFAULTnet_hostport = 26000;
34
35 char            my_ipx_address[NET_NAMELEN];
36 char            my_tcpip_address[NET_NAMELEN];
37
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);
42
43 static qboolean listening = false;
44
45 qboolean        slistInProgress = false;
46 qboolean        slistSilent = false;
47 qboolean        slistLocal = true;
48 static double   slistStartTime;
49 static int              slistLastShown;
50
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};
55
56
57 sizebuf_t               net_message;
58 int                             net_activeconnections = 0;
59
60 int messagesSent = 0;
61 int messagesReceived = 0;
62 int unreliableMessagesSent = 0;
63 int unreliableMessagesReceived = 0;
64
65 cvar_t  net_messagetimeout = {"net_messagetimeout","300"};
66 cvar_t  hostname = {"hostname", "UNNAMED"};
67
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};
77
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]
81
82 int     net_driverlevel;
83
84
85 double                  net_time;
86
87 double SetNetTime(void)
88 {
89         net_time = Sys_FloatTime();
90         return net_time;
91 }
92
93
94 /*
95 ===================
96 NET_NewQSocket
97
98 Called by drivers when a new communications endpoint is required
99 The sequence and buffer fields will be filled in properly
100 ===================
101 */
102 qsocket_t *NET_NewQSocket (void)
103 {
104         qsocket_t       *sock;
105
106         if (net_freeSockets == NULL)
107                 return NULL;
108
109         if (net_activeconnections >= svs.maxclients)
110                 return NULL;
111
112         // get one from free list
113         sock = net_freeSockets;
114         net_freeSockets = sock->next;
115
116         // add it to active list
117         sock->next = net_activeSockets;
118         net_activeSockets = sock;
119
120         sock->disconnected = false;
121         sock->connecttime = net_time;
122         strcpy (sock->address,"UNSET ADDRESS");
123         sock->driver = net_driverlevel;
124         sock->socket = 0;
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;
136
137         return sock;
138 }
139
140
141 void NET_FreeQSocket(qsocket_t *sock)
142 {
143         qsocket_t       *s;
144
145         // remove it from active list
146         if (sock == net_activeSockets)
147                 net_activeSockets = net_activeSockets->next;
148         else
149         {
150                 for (s = net_activeSockets; s; s = s->next)
151                         if (s->next == sock)
152                         {
153                                 s->next = sock->next;
154                                 break;
155                         }
156                 if (!s)
157                         Sys_Error ("NET_FreeQSocket: not active\n");
158         }
159
160         // add it to free list
161         sock->next = net_freeSockets;
162         net_freeSockets = sock;
163         sock->disconnected = true;
164 }
165
166
167 static void NET_Listen_f (void)
168 {
169         if (Cmd_Argc () != 2)
170         {
171                 Con_Printf ("\"listen\" is \"%u\"\n", listening ? 1 : 0);
172                 return;
173         }
174
175         listening = atoi(Cmd_Argv(1)) ? true : false;
176
177         for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
178         {
179                 if (net_drivers[net_driverlevel].initialized == false)
180                         continue;
181                 dfunc.Listen (listening);
182         }
183 }
184
185
186 static void MaxPlayers_f (void)
187 {
188         int     n;
189
190         if (Cmd_Argc () != 2)
191         {
192                 Con_Printf ("\"maxplayers\" is \"%u\"\n", svs.maxclients);
193                 return;
194         }
195
196         if (sv.active)
197         {
198                 Con_Printf ("maxplayers can not be changed while a server is running.\n");
199                 return;
200         }
201
202         n = atoi(Cmd_Argv(1));
203         if (n < 1)
204                 n = 1;
205         if (n > svs.maxclientslimit)
206         {
207                 n = svs.maxclientslimit;
208                 Con_Printf ("\"maxplayers\" set to \"%u\"\n", n);
209         }
210
211         if ((n == 1) && listening)
212                 Cbuf_AddText ("listen 0\n");
213
214         if ((n > 1) && (!listening))
215                 Cbuf_AddText ("listen 1\n");
216
217         svs.maxclients = n;
218         // LordHavoc: resetting deathmatch and coop was silly
219         /*
220         if (n == 1)
221                 Cvar_Set ("deathmatch", "0");
222         else
223                 Cvar_Set ("deathmatch", "1");
224         */
225 }
226
227
228 static void NET_Port_f (void)
229 {
230         int     n;
231
232         if (Cmd_Argc () != 2)
233         {
234                 Con_Printf ("\"port\" is \"%u\"\n", net_hostport);
235                 return;
236         }
237
238         n = atoi(Cmd_Argv(1));
239         if (n < 1 || n > 65534)
240         {
241                 Con_Printf ("Bad value, must be between 1 and 65534\n");
242                 return;
243         }
244
245         DEFAULTnet_hostport = n;
246         net_hostport = n;
247
248         if (listening)
249         {
250                 // force a change to the new port
251                 Cbuf_AddText ("listen 0\n");
252                 Cbuf_AddText ("listen 1\n");
253         }
254 }
255
256
257 static void PrintSlistHeader(void)
258 {
259         Con_Printf("Server          Map             Users\n");
260         Con_Printf("--------------- --------------- -----\n");
261         slistLastShown = 0;
262 }
263
264
265 static void PrintSlist(void)
266 {
267         int n;
268
269         for (n = slistLastShown; n < hostCacheCount; n++)
270         {
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);
273                 else
274                         Con_Printf("%-15.15s %-15.15s\n", hostcache[n].name, hostcache[n].map);
275         }
276         slistLastShown = n;
277 }
278
279
280 static void PrintSlistTrailer(void)
281 {
282         if (hostCacheCount)
283                 Con_Printf("== end list ==\n\n");
284         else
285                 Con_Printf("No Quake servers found.\n\n");
286 }
287
288
289 void NET_Slist_f (void)
290 {
291         if (slistInProgress)
292                 return;
293
294         if (! slistSilent)
295         {
296                 Con_Printf("Looking for Quake servers...\n");
297                 PrintSlistHeader();
298         }
299
300         slistInProgress = true;
301         slistStartTime = Sys_FloatTime();
302
303         SchedulePollProcedure(&slistSendProcedure, 0.0);
304         SchedulePollProcedure(&slistPollProcedure, 0.1);
305
306         hostCacheCount = 0;
307 }
308
309
310 static void Slist_Send(void)
311 {
312         for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
313         {
314                 if (!slistLocal && net_driverlevel == 0)
315                         continue;
316                 if (net_drivers[net_driverlevel].initialized == false)
317                         continue;
318                 dfunc.SearchForHosts (true);
319         }
320
321         if ((Sys_FloatTime() - slistStartTime) < 0.5)
322                 SchedulePollProcedure(&slistSendProcedure, 0.75);
323 }
324
325
326 static void Slist_Poll(void)
327 {
328         for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
329         {
330                 if (!slistLocal && net_driverlevel == 0)
331                         continue;
332                 if (net_drivers[net_driverlevel].initialized == false)
333                         continue;
334                 dfunc.SearchForHosts (false);
335         }
336
337         if (! slistSilent)
338                 PrintSlist();
339
340         if ((Sys_FloatTime() - slistStartTime) < 1.5)
341         {
342                 SchedulePollProcedure(&slistPollProcedure, 0.1);
343                 return;
344         }
345
346         if (! slistSilent)
347                 PrintSlistTrailer();
348         slistInProgress = false;
349         slistSilent = false;
350         slistLocal = true;
351 }
352
353
354 /*
355 ===================
356 NET_Connect
357 ===================
358 */
359
360 int hostCacheCount = 0;
361 hostcache_t hostcache[HOSTCACHESIZE];
362
363 qsocket_t *NET_Connect (char *host)
364 {
365         qsocket_t               *ret;
366         int                             n;
367         int                             numdrivers = net_numdrivers;
368
369         SetNetTime();
370
371         if (host && *host == 0)
372                 host = NULL;
373
374         if (host)
375         {
376                 if (Q_strcasecmp (host, "local") == 0)
377                 {
378                         numdrivers = 1;
379                         goto JustDoIt;
380                 }
381
382                 if (hostCacheCount)
383                 {
384                         for (n = 0; n < hostCacheCount; n++)
385                                 if (Q_strcasecmp (host, hostcache[n].name) == 0)
386                                 {
387                                         host = hostcache[n].cname;
388                                         break;
389                                 }
390                         if (n < hostCacheCount)
391                                 goto JustDoIt;
392                 }
393         }
394
395         slistSilent = host ? true : false;
396         NET_Slist_f ();
397
398         while(slistInProgress)
399                 NET_Poll();
400
401         if (host == NULL)
402         {
403                 if (hostCacheCount != 1)
404                         return NULL;
405                 host = hostcache[0].cname;
406                 Con_Printf("Connecting to...\n%s @ %s\n\n", hostcache[0].name, host);
407         }
408
409         if (hostCacheCount)
410                 for (n = 0; n < hostCacheCount; n++)
411                         if (Q_strcasecmp (host, hostcache[n].name) == 0)
412                         {
413                                 host = hostcache[n].cname;
414                                 break;
415                         }
416
417 JustDoIt:
418         for (net_driverlevel=0 ; net_driverlevel<numdrivers; net_driverlevel++)
419         {
420                 if (net_drivers[net_driverlevel].initialized == false)
421                         continue;
422                 ret = dfunc.Connect (host);
423                 if (ret)
424                         return ret;
425         }
426
427         if (host)
428         {
429                 Con_Printf("\n");
430                 PrintSlistHeader();
431                 PrintSlist();
432                 PrintSlistTrailer();
433         }
434         
435         return NULL;
436 }
437
438
439 /*
440 ===================
441 NET_CheckNewConnections
442 ===================
443 */
444
445 qsocket_t *NET_CheckNewConnections (void)
446 {
447         qsocket_t       *ret;
448
449         SetNetTime();
450
451         for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
452         {
453                 if (net_drivers[net_driverlevel].initialized == false)
454                         continue;
455                 if (net_driverlevel && listening == false)
456                         continue;
457                 ret = dfunc.CheckNewConnections ();
458                 if (ret)
459                         return ret;
460         }
461
462         return NULL;
463 }
464
465 /*
466 ===================
467 NET_Close
468 ===================
469 */
470 void NET_Close (qsocket_t *sock)
471 {
472         if (!sock)
473                 return;
474
475         if (sock->disconnected)
476                 return;
477
478         SetNetTime();
479
480         // call the driver_Close function
481         sfunc.Close (sock);
482
483         NET_FreeQSocket(sock);
484 }
485
486
487 /*
488 =================
489 NET_GetMessage
490
491 If there is a complete message, return it in net_message
492
493 returns 0 if no data is waiting
494 returns 1 if a message was received
495 returns -1 if connection is invalid
496 =================
497 */
498
499 extern void PrintStats(qsocket_t *s);
500
501 int     NET_GetMessage (qsocket_t *sock)
502 {
503         int ret;
504
505         if (!sock)
506                 return -1;
507
508         if (sock->disconnected)
509         {
510                 Con_Printf("NET_GetMessage: disconnected socket\n");
511                 return -1;
512         }
513
514         SetNetTime();
515
516         ret = sfunc.QGetMessage(sock);
517
518         // see if this connection has timed out
519         if (ret == 0 && sock->driver)
520         {
521                 if (net_time - sock->lastMessageTime > net_messagetimeout.value)
522                 {
523                         NET_Close(sock);
524                         return -1;
525                 }
526         }
527
528
529         if (ret > 0)
530         {
531                 if (sock->driver)
532                 {
533                         sock->lastMessageTime = net_time;
534                         if (ret == 1)
535                                 messagesReceived++;
536                         else if (ret == 2)
537                                 unreliableMessagesReceived++;
538                 }
539         }
540
541         return ret;
542 }
543
544
545 /*
546 ==================
547 NET_SendMessage
548
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
554 ==================
555 */
556 int NET_SendMessage (qsocket_t *sock, sizebuf_t *data)
557 {
558         int             r;
559         
560         if (!sock)
561                 return -1;
562
563         if (sock->disconnected)
564         {
565                 Con_Printf("NET_SendMessage: disconnected socket\n");
566                 return -1;
567         }
568
569         SetNetTime();
570         r = sfunc.QSendMessage(sock, data);
571         if (r == 1 && sock->driver)
572                 messagesSent++;
573         
574         return r;
575 }
576
577
578 int NET_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data)
579 {
580         int             r;
581         
582         if (!sock)
583                 return -1;
584
585         if (sock->disconnected)
586         {
587                 Con_Printf("NET_SendMessage: disconnected socket\n");
588                 return -1;
589         }
590
591         SetNetTime();
592         r = sfunc.SendUnreliableMessage(sock, data);
593         if (r == 1 && sock->driver)
594                 unreliableMessagesSent++;
595
596         return r;
597 }
598
599
600 /*
601 ==================
602 NET_CanSendMessage
603
604 Returns true or false if the given qsocket can currently accept a
605 message to be transmitted.
606 ==================
607 */
608 qboolean NET_CanSendMessage (qsocket_t *sock)
609 {
610         int             r;
611         
612         if (!sock)
613                 return false;
614
615         if (sock->disconnected)
616                 return false;
617
618         SetNetTime();
619
620         r = sfunc.CanSendMessage(sock);
621         
622         return r;
623 }
624
625
626 int NET_SendToAll(sizebuf_t *data, int blocktime)
627 {
628         double          start;
629         int                     i;
630         int                     count = 0;
631         qboolean        state1 [MAX_SCOREBOARD];
632         qboolean        state2 [MAX_SCOREBOARD];
633
634         for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
635         {
636                 if (!host_client->netconnection)
637                         continue;
638                 if (host_client->active)
639                 {
640                         if (host_client->netconnection->driver == 0)
641                         {
642                                 NET_SendMessage(host_client->netconnection, data);
643                                 state1[i] = true;
644                                 state2[i] = true;
645                                 continue;
646                         }
647                         count++;
648                         state1[i] = false;
649                         state2[i] = false;
650                 }
651                 else
652                 {
653                         state1[i] = true;
654                         state2[i] = true;
655                 }
656         }
657
658         start = Sys_FloatTime();
659         while (count)
660         {
661                 count = 0;
662                 for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
663                 {
664                         if (! state1[i])
665                         {
666                                 if (NET_CanSendMessage (host_client->netconnection))
667                                 {
668                                         state1[i] = true;
669                                         NET_SendMessage(host_client->netconnection, data);
670                                 }
671                                 else
672                                 {
673                                         NET_GetMessage (host_client->netconnection);
674                                 }
675                                 count++;
676                                 continue;
677                         }
678
679                         if (! state2[i])
680                         {
681                                 if (NET_CanSendMessage (host_client->netconnection))
682                                 {
683                                         state2[i] = true;
684                                 }
685                                 else
686                                 {
687                                         NET_GetMessage (host_client->netconnection);
688                                 }
689                                 count++;
690                                 continue;
691                         }
692                 }
693                 if ((Sys_FloatTime() - start) > blocktime)
694                         break;
695         }
696         return count;
697 }
698
699
700 //=============================================================================
701
702 /*
703 ====================
704 NET_Init
705 ====================
706 */
707
708 void NET_Init (void)
709 {
710         int                     i;
711         int                     controlSocket;
712         qsocket_t       *s;
713
714         i = COM_CheckParm ("-port");
715         if (!i)
716                 i = COM_CheckParm ("-udpport");
717         if (!i)
718                 i = COM_CheckParm ("-ipxport");
719
720         if (i)
721         {
722                 if (i < com_argc-1)
723                         DEFAULTnet_hostport = atoi (com_argv[i+1]);
724                 else
725                         Sys_Error ("NET_Init: you must specify a number after -port");
726         }
727         net_hostport = DEFAULTnet_hostport;
728
729         if (COM_CheckParm("-listen") || cls.state == ca_dedicated)
730                 listening = true;
731         net_numsockets = svs.maxclientslimit;
732         if (cls.state != ca_dedicated)
733                 net_numsockets++;
734
735         SetNetTime();
736
737         for (i = 0; i < net_numsockets; i++)
738         {
739                 s = (qsocket_t *)Hunk_AllocName(sizeof(qsocket_t), "qsocket");
740                 s->next = net_freeSockets;
741                 net_freeSockets = s;
742                 s->disconnected = true;
743         }
744
745         // allocate space for network message buffer
746         SZ_Alloc (&net_message, NET_MAXMESSAGE);
747
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);
758
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);
763
764         // initialize all the drivers
765         for (net_driverlevel=0 ; net_driverlevel<net_numdrivers ; net_driverlevel++)
766                 {
767                 controlSocket = net_drivers[net_driverlevel].Init();
768                 if (controlSocket == -1)
769                         continue;
770                 net_drivers[net_driverlevel].initialized = true;
771                 net_drivers[net_driverlevel].controlSock = controlSocket;
772                 if (listening)
773                         net_drivers[net_driverlevel].Listen (true);
774                 }
775
776         if (*my_ipx_address)
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);
780 }
781
782 /*
783 ====================
784 NET_Shutdown
785 ====================
786 */
787
788 void            NET_Shutdown (void)
789 {
790         qsocket_t       *sock;
791
792         SetNetTime();
793
794         for (sock = net_activeSockets; sock; sock = sock->next)
795                 NET_Close(sock);
796
797 //
798 // shutdown the drivers
799 //
800         for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++)
801         {
802                 if (net_drivers[net_driverlevel].initialized == true)
803                 {
804                         net_drivers[net_driverlevel].Shutdown ();
805                         net_drivers[net_driverlevel].initialized = false;
806                 }
807         }
808 }
809
810
811 static PollProcedure *pollProcedureList = NULL;
812
813 void NET_Poll(void)
814 {
815         PollProcedure *pp;
816         qboolean        useModem;
817
818         if (!configRestored)
819         {
820                 if (serialAvailable)
821                 {
822                         if (config_com_modem.value == 1.0)
823                                 useModem = true;
824                         else
825                                 useModem = false;
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);
828                 }
829                 configRestored = true;
830         }
831
832         SetNetTime();
833
834         for (pp = pollProcedureList; pp; pp = pp->next)
835         {
836                 if (pp->nextTime > net_time)
837                         break;
838                 pollProcedureList = pp->next;
839                 pp->procedure(pp->arg);
840         }
841 }
842
843
844 void SchedulePollProcedure(PollProcedure *proc, double timeOffset)
845 {
846         PollProcedure *pp, *prev;
847
848         proc->nextTime = Sys_FloatTime() + timeOffset;
849         for (pp = pollProcedureList, prev = NULL; pp; pp = pp->next)
850         {
851                 if (pp->nextTime >= proc->nextTime)
852                         break;
853                 prev = pp;
854         }
855
856         if (prev == NULL)
857         {
858                 proc->next = pollProcedureList;
859                 pollProcedureList = proc;
860                 return;
861         }
862
863         proc->next = pp;
864         prev->next = proc;
865 }