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