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