a7137ab3aea7ea599f1d95bc026904033b6b872e
[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         n = bound(1, n, MAX_SCOREBOARD);
181         if (svs.maxclients != n)
182                 Con_Printf ("\"maxplayers\" set to \"%u\"\n", n);
183
184         if ((n == 1) && listening)
185                 Cbuf_AddText ("listen 0\n");
186
187         if ((n > 1) && (!listening))
188                 Cbuf_AddText ("listen 1\n");
189
190         SV_SetMaxClients(n);
191 }
192
193
194 static void NET_Port_f (void)
195 {
196         int     n;
197
198         if (Cmd_Argc () != 2)
199         {
200                 Con_Printf ("\"port\" is \"%u\"\n", net_hostport);
201                 return;
202         }
203
204         n = atoi(Cmd_Argv(1));
205         if (n < 1 || n > 65534)
206         {
207                 Con_Printf ("Bad value, must be between 1 and 65534\n");
208                 return;
209         }
210
211         DEFAULTnet_hostport = n;
212         net_hostport = n;
213
214         if (listening)
215         {
216                 // force a change to the new port
217                 Cbuf_AddText ("listen 0\n");
218                 Cbuf_AddText ("listen 1\n");
219         }
220 }
221
222
223 static void PrintSlistHeader(void)
224 {
225         Con_Printf("Server          Map             Users\n");
226         Con_Printf("--------------- --------------- -----\n");
227         slistLastShown = 0;
228 }
229
230
231 static void PrintSlist(void)
232 {
233         int n;
234
235         for (n = slistLastShown; n < hostCacheCount; n++)
236         {
237                 if (hostcache[n].maxusers)
238                         Con_Printf("%-15.15s %-15.15s %2u/%2u\n", hostcache[n].name, hostcache[n].map, hostcache[n].users, hostcache[n].maxusers);
239                 else
240                         Con_Printf("%-15.15s %-15.15s\n", hostcache[n].name, hostcache[n].map);
241         }
242         slistLastShown = n;
243 }
244
245
246 static void PrintSlistTrailer(void)
247 {
248         if (hostCacheCount)
249                 Con_Printf("== end list ==\n\n");
250         else
251                 Con_Printf("No Quake servers found.\n\n");
252 }
253
254
255 void NET_Slist_f (void)
256 {
257         if (slistInProgress)
258                 return;
259
260         if (! slistSilent)
261         {
262                 Con_Printf("Looking for Quake servers...\n");
263                 PrintSlistHeader();
264         }
265
266         slistInProgress = true;
267         slistStartTime = Sys_DoubleTime();
268
269         SchedulePollProcedure(&slistSendProcedure, 0.0);
270         SchedulePollProcedure(&slistPollProcedure, 0.1);
271
272         hostCacheCount = 0;
273 }
274
275
276 static void Slist_Send(void)
277 {
278         for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
279         {
280                 if (!slistLocal && net_driverlevel == 0)
281                         continue;
282                 if (net_drivers[net_driverlevel].initialized == false)
283                         continue;
284                 dfunc.SearchForHosts (true);
285         }
286
287         if ((Sys_DoubleTime() - slistStartTime) < 0.5)
288                 SchedulePollProcedure(&slistSendProcedure, 0.75);
289 }
290
291
292 static void Slist_Poll(void)
293 {
294         for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
295         {
296                 if (!slistLocal && net_driverlevel == 0)
297                         continue;
298                 if (net_drivers[net_driverlevel].initialized == false)
299                         continue;
300                 dfunc.SearchForHosts (false);
301         }
302
303         if (! slistSilent)
304                 PrintSlist();
305
306         if ((Sys_DoubleTime() - slistStartTime) < 1.5)
307         {
308                 SchedulePollProcedure(&slistPollProcedure, 0.1);
309                 return;
310         }
311
312         if (! slistSilent)
313                 PrintSlistTrailer();
314         slistInProgress = false;
315         slistSilent = false;
316         slistLocal = true;
317 }
318
319
320 /*
321 ===================
322 NET_Connect
323 ===================
324 */
325
326 int hostCacheCount = 0;
327 hostcache_t hostcache[HOSTCACHESIZE];
328
329 qsocket_t *NET_Connect (char *host)
330 {
331         qsocket_t               *ret;
332         int                             n;
333         int                             numdrivers = net_numdrivers;
334
335         SetNetTime();
336
337         if (host && *host == 0)
338                 host = NULL;
339
340         if (host)
341         {
342                 if (Q_strcasecmp (host, "local") == 0)
343                 {
344                         numdrivers = 1;
345                         goto JustDoIt;
346                 }
347
348                 if (hostCacheCount)
349                 {
350                         for (n = 0; n < hostCacheCount; n++)
351                                 if (Q_strcasecmp (host, hostcache[n].name) == 0)
352                                 {
353                                         host = hostcache[n].cname;
354                                         break;
355                                 }
356                         if (n < hostCacheCount)
357                                 goto JustDoIt;
358                 }
359         }
360
361         slistSilent = host ? true : false;
362         NET_Slist_f ();
363
364         while(slistInProgress)
365                 NET_Poll();
366
367         if (host == NULL)
368         {
369                 if (hostCacheCount != 1)
370                         return NULL;
371                 host = hostcache[0].cname;
372                 Con_Printf("Connecting to...\n%s @ %s\n\n", hostcache[0].name, host);
373         }
374
375         if (hostCacheCount)
376                 for (n = 0; n < hostCacheCount; n++)
377                         if (Q_strcasecmp (host, hostcache[n].name) == 0)
378                         {
379                                 host = hostcache[n].cname;
380                                 break;
381                         }
382
383 JustDoIt:
384         for (net_driverlevel=0 ; net_driverlevel<numdrivers; net_driverlevel++)
385         {
386                 if (net_drivers[net_driverlevel].initialized == false)
387                         continue;
388                 ret = dfunc.Connect (host);
389                 if (ret)
390                         return ret;
391         }
392
393         if (host)
394         {
395                 Con_Printf("\n");
396                 PrintSlistHeader();
397                 PrintSlist();
398                 PrintSlistTrailer();
399         }
400         
401         return NULL;
402 }
403
404
405 /*
406 ===================
407 NET_CheckNewConnections
408 ===================
409 */
410
411 qsocket_t *NET_CheckNewConnections (void)
412 {
413         qsocket_t       *ret;
414
415         SetNetTime();
416
417         for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
418         {
419                 if (net_drivers[net_driverlevel].initialized == false)
420                         continue;
421                 if (net_driverlevel && listening == false)
422                         continue;
423                 ret = dfunc.CheckNewConnections ();
424                 if (ret)
425                         return ret;
426         }
427
428         return NULL;
429 }
430
431 /*
432 ===================
433 NET_Close
434 ===================
435 */
436 void NET_Close (qsocket_t *sock)
437 {
438         if (!sock)
439                 return;
440
441         if (sock->disconnected)
442                 return;
443
444         SetNetTime();
445
446         // call the driver_Close function
447         sfunc.Close (sock);
448
449         NET_FreeQSocket(sock);
450 }
451
452
453 /*
454 =================
455 NET_GetMessage
456
457 If there is a complete message, return it in net_message
458
459 returns 0 if no data is waiting
460 returns 1 if a message was received
461 returns -1 if connection is invalid
462 =================
463 */
464
465 extern void PrintStats(qsocket_t *s);
466
467 int     NET_GetMessage (qsocket_t *sock)
468 {
469         int ret;
470
471         if (!sock)
472                 return -1;
473
474         if (sock->disconnected)
475         {
476                 Con_Printf("NET_GetMessage: disconnected socket\n");
477                 return -1;
478         }
479
480         SetNetTime();
481
482         ret = sfunc.QGetMessage(sock);
483
484         // see if this connection has timed out
485         if (ret == 0 && sock->driver)
486         {
487                 if (net_time - sock->lastMessageTime > net_messagetimeout.value)
488                 {
489                         NET_Close(sock);
490                         return -1;
491                 }
492         }
493
494
495         if (ret > 0)
496         {
497                 if (sock->driver)
498                 {
499                         sock->lastMessageTime = net_time;
500                         if (ret == 1)
501                                 messagesReceived++;
502                         else if (ret == 2)
503                                 unreliableMessagesReceived++;
504                 }
505         }
506
507         return ret;
508 }
509
510
511 /*
512 ==================
513 NET_SendMessage
514
515 Try to send a complete length+message unit over the reliable stream.
516 returns 0 if the message cannot be delivered reliably, but the connection
517                 is still considered valid
518 returns 1 if the message was sent properly
519 returns -1 if the connection died
520 ==================
521 */
522 int NET_SendMessage (qsocket_t *sock, sizebuf_t *data)
523 {
524         int             r;
525         
526         if (!sock)
527                 return -1;
528
529         if (sock->disconnected)
530         {
531                 Con_Printf("NET_SendMessage: disconnected socket\n");
532                 return -1;
533         }
534
535         SetNetTime();
536         r = sfunc.QSendMessage(sock, data);
537         if (r == 1 && sock->driver)
538                 messagesSent++;
539
540         return r;
541 }
542
543
544 int NET_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data)
545 {
546         int             r;
547         
548         if (!sock)
549                 return -1;
550
551         if (sock->disconnected)
552         {
553                 Con_Printf("NET_SendMessage: disconnected socket\n");
554                 return -1;
555         }
556
557         SetNetTime();
558         r = sfunc.SendUnreliableMessage(sock, data);
559         if (r == 1 && sock->driver)
560                 unreliableMessagesSent++;
561
562         return r;
563 }
564
565
566 /*
567 ==================
568 NET_CanSendMessage
569
570 Returns true or false if the given qsocket can currently accept a
571 message to be transmitted.
572 ==================
573 */
574 qboolean NET_CanSendMessage (qsocket_t *sock)
575 {
576         int             r;
577         
578         if (!sock)
579                 return false;
580
581         if (sock->disconnected)
582                 return false;
583
584         SetNetTime();
585
586         r = sfunc.CanSendMessage(sock);
587         
588         return r;
589 }
590
591
592 int NET_SendToAll(sizebuf_t *data, int blocktime)
593 {
594         double          start;
595         int                     i;
596         int                     count = 0;
597         qboolean        state1 [MAX_SCOREBOARD];
598         qboolean        state2 [MAX_SCOREBOARD];
599
600         for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
601         {
602                 if (!host_client->netconnection)
603                         continue;
604                 if (host_client->active)
605                 {
606                         if (host_client->netconnection->driver == 0)
607                         {
608                                 NET_SendMessage(host_client->netconnection, data);
609                                 state1[i] = true;
610                                 state2[i] = true;
611                                 continue;
612                         }
613                         count++;
614                         state1[i] = false;
615                         state2[i] = false;
616                 }
617                 else
618                 {
619                         state1[i] = true;
620                         state2[i] = true;
621                 }
622         }
623
624         start = Sys_DoubleTime();
625         while (count)
626         {
627                 count = 0;
628                 for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
629                 {
630                         if (! state1[i])
631                         {
632                                 if (NET_CanSendMessage (host_client->netconnection))
633                                 {
634                                         state1[i] = true;
635                                         NET_SendMessage(host_client->netconnection, data);
636                                 }
637                                 else
638                                 {
639                                         NET_GetMessage (host_client->netconnection);
640                                 }
641                                 count++;
642                                 continue;
643                         }
644
645                         if (! state2[i])
646                         {
647                                 if (NET_CanSendMessage (host_client->netconnection))
648                                 {
649                                         state2[i] = true;
650                                 }
651                                 else
652                                 {
653                                         NET_GetMessage (host_client->netconnection);
654                                 }
655                                 count++;
656                                 continue;
657                         }
658                 }
659                 if ((Sys_DoubleTime() - start) > blocktime)
660                         break;
661         }
662         return count;
663 }
664
665
666 //=============================================================================
667
668 /*
669 ====================
670 NET_Init
671 ====================
672 */
673
674 void NET_Init (void)
675 {
676         int                     i;
677         int                     controlSocket;
678
679         i = COM_CheckParm ("-port");
680         if (!i)
681                 i = COM_CheckParm ("-udpport");
682         if (!i)
683                 i = COM_CheckParm ("-ipxport");
684
685         if (i)
686         {
687                 if (i < com_argc-1)
688                         DEFAULTnet_hostport = atoi (com_argv[i+1]);
689                 else
690                         Sys_Error ("NET_Init: you must specify a number after -port");
691         }
692         net_hostport = DEFAULTnet_hostport;
693
694         if (COM_CheckParm("-listen") || cls.state == ca_dedicated || gamemode == GAME_TRANSFUSION)
695                 listening = true;
696
697         SetNetTime();
698
699         net_mempool = Mem_AllocPool("qsocket");
700
701         // allocate space for network message buffer
702         SZ_Alloc (&net_message, NET_MAXMESSAGE, "net_message");
703
704         Cvar_RegisterVariable (&net_messagetimeout);
705         Cvar_RegisterVariable (&hostname);
706
707         Cmd_AddCommand ("slist", NET_Slist_f);
708         Cmd_AddCommand ("listen", NET_Listen_f);
709         Cmd_AddCommand ("maxplayers", MaxPlayers_f);
710         Cmd_AddCommand ("port", NET_Port_f);
711
712         // initialize all the drivers
713         for (net_driverlevel=0 ; net_driverlevel<net_numdrivers ; net_driverlevel++)
714                 {
715                 controlSocket = net_drivers[net_driverlevel].Init();
716                 if (controlSocket == -1)
717                         continue;
718                 net_drivers[net_driverlevel].initialized = true;
719                 net_drivers[net_driverlevel].controlSock = controlSocket;
720                 if (listening)
721                         net_drivers[net_driverlevel].Listen (true);
722                 }
723
724         if (*my_ipx_address)
725                 Con_DPrintf("IPX address %s\n", my_ipx_address);
726         if (*my_tcpip_address)
727                 Con_DPrintf("TCP/IP address %s\n", my_tcpip_address);
728 }
729
730 /*
731 ====================
732 NET_Shutdown
733 ====================
734 */
735
736 void NET_Shutdown (void)
737 {
738         SetNetTime();
739
740         while (net_activeSockets)
741                 NET_Close(net_activeSockets);
742
743 //
744 // shutdown the drivers
745 //
746         for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++)
747         {
748                 if (net_drivers[net_driverlevel].initialized == true)
749                 {
750                         net_drivers[net_driverlevel].Shutdown ();
751                         net_drivers[net_driverlevel].initialized = false;
752                 }
753         }
754
755         Mem_FreePool(&net_mempool);
756 }
757
758
759 static PollProcedure *pollProcedureList = NULL;
760
761 void NET_Poll(void)
762 {
763         PollProcedure *pp;
764
765         if (!configRestored)
766                 configRestored = true;
767
768         SetNetTime();
769
770         for (pp = pollProcedureList; pp; pp = pp->next)
771         {
772                 if (pp->nextTime > net_time)
773                         break;
774                 pollProcedureList = pp->next;
775                 pp->procedure(pp->arg);
776         }
777 }
778
779
780 void SchedulePollProcedure(PollProcedure *proc, double timeOffset)
781 {
782         PollProcedure *pp, *prev;
783
784         proc->nextTime = Sys_DoubleTime() + timeOffset;
785         for (pp = pollProcedureList, prev = NULL; pp; pp = pp->next)
786         {
787                 if (pp->nextTime >= proc->nextTime)
788                         break;
789                 prev = pp;
790         }
791
792         if (prev == NULL)
793         {
794                 proc->next = pollProcedureList;
795                 pollProcedureList = proc;
796                 return;
797         }
798
799         proc->next = pp;
800         prev->next = proc;
801 }
802