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