]> icculus.org git repositories - divverent/darkplaces.git/blob - net_main.c
cleanup of precache messages and assorted comments
[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 #include "net_master.h"
24
25 qsocket_t *net_activeSockets = NULL;
26 mempool_t *net_mempool;
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 static void InetSlist_Send(void);
51 static void InetSlist_Poll(void);
52 PollProcedure   inetSlistSendProcedure = {NULL, 0.0, InetSlist_Send};
53 PollProcedure   inetSlistPollProcedure = {NULL, 0.0, InetSlist_Poll};
54
55
56 sizebuf_t               net_message;
57 int                             net_activeconnections = 0;
58
59 int messagesSent = 0;
60 int messagesReceived = 0;
61 int unreliableMessagesSent = 0;
62 int unreliableMessagesReceived = 0;
63
64 cvar_t  net_messagetimeout = {0, "net_messagetimeout","300"};
65 cvar_t  hostname = {CVAR_SAVE, "hostname", "UNNAMED"};
66
67 qboolean        configRestored = false;
68
69 // these two macros are to make the code more readable
70 #define sfunc   net_drivers[sock->driver]
71 #define dfunc   net_drivers[net_driverlevel]
72
73 int     net_driverlevel;
74
75 /*
76 #define SLSERVERS 1024
77 #define SLNAME 40
78 #define SLMAPNAME 16
79 #define SLMODNAME 16
80 typedef struct slserver_s
81 {
82         unsigned int ipaddr;
83         unsigned short port;
84         unsigned short ping;
85         char name[SLNAME];
86         char mapname[SLMAPNAME];
87         char modname[SLMODNAME];
88 }
89 slserver_t;
90
91 slserver_t sl_server[SLSERVERS];
92 int sl_numservers = 0;
93
94 void SL_ClearServers(void)
95 {
96         sl_numservers = 0;
97 }
98
99 slserver_t *SL_FindServer(unsigned int ipaddr, unsigned short port)
100 {
101         int i;
102         slserver_t *sl;
103         for (i = 0, sl = sl_server;i < sl_numservers;i++, sl++)
104                 if (sl->ipaddr == ipaddr && sl->port == port)
105                         return;
106 }
107
108 void SL_AddServer(unsigned int ipaddr, unsigned short port)
109 {
110         if (SL_FindServer(ipaddr, port))
111                 return;
112         memset(sl_server + sl_numservers, 0, sizeof(slserver_t));
113         sl_server[sl_numservers].ipaddr = ipaddr;
114         sl_server[sl_numservers].port = port;
115         sl_server[sl_numservers].ping = 0xFFFF;
116         sl_numservers++;
117 }
118
119 void SL_UpdateServerName(unsigned int ipaddr, unsigned short port, const char *name);
120 {
121         int namelen;
122         slserver_t *sl;
123         sl = SL_FindServer(ipaddr, port);
124         if (sl == NULL)
125                 return;
126         memset(sl->name, 0, sizeof(sl->name));
127         namelen = strlen(name);
128         if (namelen > sizeof(sl->name) - 1)
129                 namelen = sizeof(sl->name) - 1;
130         if (namelen)
131                 memcpy(sl->name, name, namelen);
132 }
133
134 void SL_UpdateServerModName(unsigned int ipaddr, unsigned short port, const char *name);
135 {
136         int namelen;
137         slserver_t *sl;
138         sl = SL_FindServer(ipaddr, port);
139         if (sl == NULL)
140                 return;
141         memset(sl->modname, 0, sizeof(sl->modname));
142         namelen = strlen(name);
143         if (namelen > sizeof(sl->modname) - 1)
144                 namelen = sizeof(sl->modname) - 1;
145         if (namelen)
146                 memcpy(sl->modname, name, namelen);
147 }
148
149 void SL_UpdateServerMapName(unsigned int ipaddr, unsigned short port, const char *name);
150 {
151         int namelen;
152         slserver_t *sl;
153         sl = SL_FindServer(ipaddr, port);
154         if (sl == NULL)
155                 return;
156         memset(sl->mapname, 0, sizeof(sl->mapname));
157         namelen = strlen(name);
158         if (namelen > sizeof(sl->mapname) - 1)
159                 namelen = sizeof(sl->mapname) - 1;
160         if (namelen)
161                 memcpy(sl->mapname, name, namelen);
162 }
163
164 void SL_UpdateServerPing(unsigned int ipaddr, unsigned short port, float ping);
165 {
166         int i;
167         slserver_t *sl;
168         sl = SL_FindServer(ipaddr, port);
169         if (sl == NULL)
170                 return;
171         i = ping * 1000.0;
172         sl->ping = bound(0, i, 9999);
173 }
174 */
175
176
177 double                  net_time;
178
179 double SetNetTime(void)
180 {
181         net_time = Sys_DoubleTime();
182         return net_time;
183 }
184
185
186 /*
187 ===================
188 NET_NewQSocket
189
190 Called by drivers when a new communications endpoint is required
191 The sequence and buffer fields will be filled in properly
192 ===================
193 */
194 qsocket_t *NET_NewQSocket (void)
195 {
196         qsocket_t       *sock;
197
198         if (net_activeconnections >= svs.maxclients)
199                 return NULL;
200
201         sock = Mem_Alloc(net_mempool, sizeof(qsocket_t));
202
203         // add it to active list
204         sock->next = net_activeSockets;
205         net_activeSockets = sock;
206
207         sock->disconnected = false;
208         sock->connecttime = net_time;
209         strcpy (sock->address,"UNSET ADDRESS");
210         sock->driver = net_driverlevel;
211         sock->socket = 0;
212         sock->driverdata = NULL;
213         sock->canSend = true;
214         sock->sendNext = false;
215         sock->lastMessageTime = net_time;
216         sock->ackSequence = 0;
217         sock->sendSequence = 0;
218         sock->unreliableSendSequence = 0;
219         sock->sendMessageLength = 0;
220         sock->receiveSequence = 0;
221         sock->unreliableReceiveSequence = 0;
222         sock->receiveMessageLength = 0;
223
224         return sock;
225 }
226
227
228 void NET_FreeQSocket(qsocket_t *sock)
229 {
230         qsocket_t       *s;
231
232         // remove it from active list
233         if (sock == net_activeSockets)
234                 net_activeSockets = net_activeSockets->next;
235         else
236         {
237                 for (s = net_activeSockets; s; s = s->next)
238                         if (s->next == sock)
239                         {
240                                 s->next = sock->next;
241                                 break;
242                         }
243                 if (!s)
244                         Sys_Error ("NET_FreeQSocket: not active\n");
245         }
246
247         Mem_Free(sock);
248 }
249
250
251 static void NET_Listen_f (void)
252 {
253         if (Cmd_Argc () != 2)
254         {
255                 Con_Printf ("\"listen\" is \"%u\"\n", listening ? 1 : 0);
256                 return;
257         }
258
259         listening = atoi(Cmd_Argv(1)) ? true : false;
260
261         for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
262         {
263                 if (net_drivers[net_driverlevel].initialized == false)
264                         continue;
265                 dfunc.Listen (listening);
266         }
267 }
268
269
270 static void MaxPlayers_f (void)
271 {
272         int n;
273
274         if (Cmd_Argc () != 2)
275         {
276                 Con_Printf ("\"maxplayers\" is \"%u\"\n", svs.maxclients);
277                 return;
278         }
279
280         if (sv.active)
281         {
282                 Con_Printf ("maxplayers can not be changed while a server is running.\n");
283                 return;
284         }
285
286         n = atoi(Cmd_Argv(1));
287         n = bound(1, n, MAX_SCOREBOARD);
288         if (svs.maxclients != n)
289                 Con_Printf ("\"maxplayers\" set to \"%u\"\n", n);
290
291         if ((n == 1) && listening)
292                 Cbuf_AddText ("listen 0\n");
293
294         if ((n > 1) && (!listening))
295                 Cbuf_AddText ("listen 1\n");
296
297         SV_SetMaxClients(n);
298 }
299
300
301 static void NET_Port_f (void)
302 {
303         int     n;
304
305         if (Cmd_Argc () != 2)
306         {
307                 Con_Printf ("\"port\" is \"%u\"\n", net_hostport);
308                 return;
309         }
310
311         n = atoi(Cmd_Argv(1));
312         if (n < 1 || n > 65534)
313         {
314                 Con_Printf ("Bad value, must be between 1 and 65534\n");
315                 return;
316         }
317
318         DEFAULTnet_hostport = n;
319         net_hostport = n;
320
321         if (listening)
322         {
323                 // force a change to the new port
324                 Cbuf_AddText ("listen 0\n");
325                 Cbuf_AddText ("listen 1\n");
326         }
327 }
328
329
330 static void NET_Heartbeat_f (void)
331 {
332         NET_Heartbeat (2);
333 }
334
335
336 static void PrintSlistHeader(void)
337 {
338         Con_Printf("Server          Map             Users\n");
339         Con_Printf("--------------- --------------- -----\n");
340         slistLastShown = 0;
341 }
342
343
344 static void PrintSlist(void)
345 {
346         int n;
347
348         for (n = slistLastShown; n < hostCacheCount; n++)
349         {
350                 if (hostcache[n].maxusers)
351                         Con_Printf("%-15.15s %-15.15s %2u/%2u\n", hostcache[n].name, hostcache[n].map, hostcache[n].users, hostcache[n].maxusers);
352                 else
353                         Con_Printf("%-15.15s %-15.15s\n", hostcache[n].name, hostcache[n].map);
354         }
355         slistLastShown = n;
356 }
357
358
359 static void PrintSlistTrailer(void)
360 {
361         if (hostCacheCount)
362                 Con_Printf("== end list ==\n\n");
363         else
364         {
365                 if (gamemode == GAME_TRANSFUSION)
366                         Con_Printf("No Transfusion servers found.\n\n");
367                 else
368                         Con_Printf("No Quake servers found.\n\n");
369         }
370 }
371
372
373 void NET_SlistCommon (PollProcedure *sendProcedure, PollProcedure *pollProcedure)
374 {
375         if (slistInProgress)
376                 return;
377
378         if (! slistSilent)
379         {
380                 if (gamemode == GAME_TRANSFUSION)
381                         Con_Printf("Looking for Transfusion servers...\n");
382                 else
383                         Con_Printf("Looking for Quake servers...\n");
384                 PrintSlistHeader();
385         }
386
387         slistInProgress = true;
388         slistStartTime = Sys_DoubleTime();
389
390         SchedulePollProcedure(sendProcedure, 0.0);
391         SchedulePollProcedure(pollProcedure, 0.1);
392
393         hostCacheCount = 0;
394 }
395
396
397 void NET_Slist_f (void)
398 {
399         NET_SlistCommon (&slistSendProcedure, &slistPollProcedure);
400 }
401
402
403 void NET_InetSlist_f (void)
404 {
405         NET_SlistCommon (&inetSlistSendProcedure, &inetSlistPollProcedure);
406 }
407
408
409 static void Slist_Send(void)
410 {
411         for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
412         {
413                 if (!slistLocal && net_driverlevel == 0)
414                         continue;
415                 if (net_drivers[net_driverlevel].initialized == false)
416                         continue;
417                 dfunc.SearchForHosts (true);
418         }
419
420         if ((Sys_DoubleTime() - slistStartTime) < 0.5)
421                 SchedulePollProcedure(&slistSendProcedure, 0.75);
422 }
423
424
425 static void Slist_Poll(void)
426 {
427         for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
428         {
429                 if (!slistLocal && net_driverlevel == 0)
430                         continue;
431                 if (net_drivers[net_driverlevel].initialized == false)
432                         continue;
433                 dfunc.SearchForHosts (false);
434         }
435
436         if (! slistSilent)
437                 PrintSlist();
438
439         if ((Sys_DoubleTime() - slistStartTime) < 1.5)
440         {
441                 SchedulePollProcedure(&slistPollProcedure, 0.1);
442                 return;
443         }
444
445         if (! slistSilent)
446                 PrintSlistTrailer();
447         slistInProgress = false;
448         slistSilent = false;
449         slistLocal = true;
450 }
451
452
453 static void InetSlist_Send(void)
454 {
455         const char* host;
456
457         if (!slistInProgress)
458                 return;
459
460         while ((host = Master_BuildGetServers ()) != NULL)
461         {
462                 for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
463                 {
464                         if (!slistLocal && net_driverlevel == 0)
465                                 continue;
466                         if (net_drivers[net_driverlevel].initialized == false)
467                                 continue;
468                         dfunc.SearchForInetHosts (host);
469                 }
470         }
471
472         if ((Sys_DoubleTime() - slistStartTime) < 3.5)
473                 SchedulePollProcedure(&inetSlistSendProcedure, 1.0);
474 }
475
476
477 static void InetSlist_Poll(void)
478 {
479         for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
480         {
481                 if (!slistLocal && net_driverlevel == 0)
482                         continue;
483                 if (net_drivers[net_driverlevel].initialized == false)
484                         continue;
485                 // We stop as soon as we have one answer (FIXME: bad...)
486                 if (dfunc.SearchForInetHosts (NULL))
487                         slistInProgress = false;
488         }
489
490         if (! slistSilent)
491                 PrintSlist();
492
493         if (slistInProgress && (Sys_DoubleTime() - slistStartTime) < 4.0)
494         {
495                 SchedulePollProcedure(&inetSlistPollProcedure, 0.1);
496                 return;
497         }
498
499         if (! slistSilent)
500                 PrintSlistTrailer();
501         slistInProgress = false;
502         slistSilent = false;
503         slistLocal = true;
504 }
505
506
507 /*
508 ===================
509 NET_Connect
510 ===================
511 */
512
513 int hostCacheCount = 0;
514 hostcache_t hostcache[HOSTCACHESIZE];
515
516 qsocket_t *NET_Connect (char *host)
517 {
518         qsocket_t               *ret;
519         int                             n;
520         int                             numdrivers = net_numdrivers;
521
522         SetNetTime();
523
524         if (host && *host == 0)
525                 host = NULL;
526
527         if (host)
528         {
529                 if (Q_strcasecmp (host, "local") == 0)
530                 {
531                         numdrivers = 1;
532                         goto JustDoIt;
533                 }
534
535                 if (hostCacheCount)
536                 {
537                         for (n = 0; n < hostCacheCount; n++)
538                                 if (Q_strcasecmp (host, hostcache[n].name) == 0)
539                                 {
540                                         host = hostcache[n].cname;
541                                         break;
542                                 }
543                         if (n < hostCacheCount)
544                                 goto JustDoIt;
545                 }
546         }
547
548         slistSilent = host ? true : false;
549         NET_Slist_f ();
550
551         while(slistInProgress)
552                 NET_Poll();
553
554         if (host == NULL)
555         {
556                 if (hostCacheCount != 1)
557                         return NULL;
558                 host = hostcache[0].cname;
559                 Con_Printf("Connecting to...\n%s @ %s\n\n", hostcache[0].name, host);
560         }
561
562         if (hostCacheCount)
563                 for (n = 0; n < hostCacheCount; n++)
564                         if (Q_strcasecmp (host, hostcache[n].name) == 0)
565                         {
566                                 host = hostcache[n].cname;
567                                 break;
568                         }
569
570 JustDoIt:
571         for (net_driverlevel=0 ; net_driverlevel<numdrivers; net_driverlevel++)
572         {
573                 if (net_drivers[net_driverlevel].initialized == false)
574                         continue;
575                 ret = dfunc.Connect (host);
576                 if (ret)
577                         return ret;
578         }
579
580         if (host)
581         {
582                 Con_Printf("\n");
583                 PrintSlistHeader();
584                 PrintSlist();
585                 PrintSlistTrailer();
586         }
587         
588         return NULL;
589 }
590
591
592 /*
593 ===================
594 NET_CheckNewConnections
595 ===================
596 */
597
598 qsocket_t *NET_CheckNewConnections (void)
599 {
600         qsocket_t       *ret;
601
602         SetNetTime();
603
604         for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
605         {
606                 if (net_drivers[net_driverlevel].initialized == false)
607                         continue;
608                 if (net_driverlevel && listening == false)
609                         continue;
610                 ret = dfunc.CheckNewConnections ();
611                 if (ret)
612                         return ret;
613         }
614
615         return NULL;
616 }
617
618 /*
619 ===================
620 NET_Close
621 ===================
622 */
623 void NET_Close (qsocket_t *sock)
624 {
625         if (!sock)
626                 return;
627
628         if (sock->disconnected)
629                 return;
630
631         SetNetTime();
632
633         // call the driver_Close function
634         sfunc.Close (sock);
635
636         NET_FreeQSocket(sock);
637 }
638
639
640 /*
641 =================
642 NET_GetMessage
643
644 If there is a complete message, return it in net_message
645
646 returns 0 if no data is waiting
647 returns 1 if a message was received
648 returns -1 if connection is invalid
649 =================
650 */
651
652 extern void PrintStats(qsocket_t *s);
653
654 int     NET_GetMessage (qsocket_t *sock)
655 {
656         int ret;
657
658         if (!sock)
659                 return -1;
660
661         if (sock->disconnected)
662         {
663                 Con_Printf("NET_GetMessage: disconnected socket\n");
664                 return -1;
665         }
666
667         SetNetTime();
668
669         ret = sfunc.QGetMessage(sock);
670
671         // see if this connection has timed out
672         if (ret == 0 && sock->driver)
673         {
674                 if (net_time - sock->lastMessageTime > net_messagetimeout.value)
675                 {
676                         NET_Close(sock);
677                         return -1;
678                 }
679         }
680
681
682         if (ret > 0)
683         {
684                 if (sock->driver)
685                 {
686                         sock->lastMessageTime = net_time;
687                         if (ret == 1)
688                                 messagesReceived++;
689                         else if (ret == 2)
690                                 unreliableMessagesReceived++;
691                 }
692         }
693
694         return ret;
695 }
696
697
698 /*
699 ==================
700 NET_SendMessage
701
702 Try to send a complete length+message unit over the reliable stream.
703 returns 0 if the message cannot be delivered reliably, but the connection
704                 is still considered valid
705 returns 1 if the message was sent properly
706 returns -1 if the connection died
707 ==================
708 */
709 int NET_SendMessage (qsocket_t *sock, sizebuf_t *data)
710 {
711         int             r;
712         
713         if (!sock)
714                 return -1;
715
716         if (sock->disconnected)
717         {
718                 Con_Printf("NET_SendMessage: disconnected socket\n");
719                 return -1;
720         }
721
722         SetNetTime();
723         r = sfunc.QSendMessage(sock, data);
724         if (r == 1 && sock->driver)
725                 messagesSent++;
726
727         return r;
728 }
729
730
731 int NET_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data)
732 {
733         int             r;
734         
735         if (!sock)
736                 return -1;
737
738         if (sock->disconnected)
739         {
740                 Con_Printf("NET_SendMessage: disconnected socket\n");
741                 return -1;
742         }
743
744         SetNetTime();
745         r = sfunc.SendUnreliableMessage(sock, data);
746         if (r == 1 && sock->driver)
747                 unreliableMessagesSent++;
748
749         return r;
750 }
751
752
753 /*
754 ==================
755 NET_CanSendMessage
756
757 Returns true or false if the given qsocket can currently accept a
758 message to be transmitted.
759 ==================
760 */
761 qboolean NET_CanSendMessage (qsocket_t *sock)
762 {
763         int             r;
764         
765         if (!sock)
766                 return false;
767
768         if (sock->disconnected)
769                 return false;
770
771         SetNetTime();
772
773         r = sfunc.CanSendMessage(sock);
774         
775         return r;
776 }
777
778
779 /*
780 ====================
781 NET_Heartbeat
782
783 Send an heartbeat to the master server(s)
784 ====================
785 */
786 void NET_Heartbeat (int priority)
787 {
788         const char* host;
789
790         if (! Master_AllowHeartbeat (priority))
791                 return;
792
793         while ((host = Master_BuildHeartbeat ()) != NULL)
794         {
795                 for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
796                 {
797                         if (net_drivers[net_driverlevel].initialized == false)
798                                 continue;
799                         if (net_driverlevel && listening == false)
800                                 continue;
801                         dfunc.Heartbeat (host);
802                 }
803         }
804 }
805
806
807 int NET_SendToAll(sizebuf_t *data, int blocktime)
808 {
809         double          start;
810         int                     i;
811         int                     count = 0;
812         qboolean        state1 [MAX_SCOREBOARD];
813         qboolean        state2 [MAX_SCOREBOARD];
814
815         for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
816         {
817                 if (!host_client->netconnection)
818                         continue;
819                 if (host_client->active)
820                 {
821                         if (host_client->netconnection->driver == 0)
822                         {
823                                 NET_SendMessage(host_client->netconnection, data);
824                                 state1[i] = true;
825                                 state2[i] = true;
826                                 continue;
827                         }
828                         count++;
829                         state1[i] = false;
830                         state2[i] = false;
831                 }
832                 else
833                 {
834                         state1[i] = true;
835                         state2[i] = true;
836                 }
837         }
838
839         start = Sys_DoubleTime();
840         while (count)
841         {
842                 count = 0;
843                 for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
844                 {
845                         if (! state1[i])
846                         {
847                                 if (NET_CanSendMessage (host_client->netconnection))
848                                 {
849                                         state1[i] = true;
850                                         NET_SendMessage(host_client->netconnection, data);
851                                 }
852                                 else
853                                 {
854                                         NET_GetMessage (host_client->netconnection);
855                                 }
856                                 count++;
857                                 continue;
858                         }
859
860                         if (! state2[i])
861                         {
862                                 if (NET_CanSendMessage (host_client->netconnection))
863                                 {
864                                         state2[i] = true;
865                                 }
866                                 else
867                                 {
868                                         NET_GetMessage (host_client->netconnection);
869                                 }
870                                 count++;
871                                 continue;
872                         }
873                 }
874                 if ((Sys_DoubleTime() - start) > blocktime)
875                         break;
876         }
877         return count;
878 }
879
880
881 //=============================================================================
882
883 /*
884 ====================
885 NET_Init
886 ====================
887 */
888
889 void NET_Init (void)
890 {
891         int                     i;
892         int                     controlSocket;
893
894         i = COM_CheckParm ("-port");
895         if (!i)
896                 i = COM_CheckParm ("-udpport");
897         if (!i)
898                 i = COM_CheckParm ("-ipxport");
899
900         if (i)
901         {
902                 if (i < com_argc-1)
903                         DEFAULTnet_hostport = atoi (com_argv[i+1]);
904                 else
905                         Sys_Error ("NET_Init: you must specify a number after -port");
906         }
907         net_hostport = DEFAULTnet_hostport;
908
909         if (COM_CheckParm("-listen") || cls.state == ca_dedicated || gamemode == GAME_TRANSFUSION)
910                 listening = true;
911
912         SetNetTime();
913
914         net_mempool = Mem_AllocPool("qsocket");
915
916         // allocate space for network message buffer
917         SZ_Alloc (&net_message, NET_MAXMESSAGE, "net_message");
918
919         Cvar_RegisterVariable (&net_messagetimeout);
920         Cvar_RegisterVariable (&hostname);
921
922         Cmd_AddCommand ("net_slist", NET_Slist_f);
923         Cmd_AddCommand ("net_inetslist", NET_InetSlist_f);
924         Cmd_AddCommand ("listen", NET_Listen_f);
925         Cmd_AddCommand ("maxplayers", MaxPlayers_f);
926         Cmd_AddCommand ("port", NET_Port_f);
927         Cmd_AddCommand ("heartbeat", NET_Heartbeat_f);
928
929         // initialize all the drivers
930         for (net_driverlevel=0 ; net_driverlevel<net_numdrivers ; net_driverlevel++)
931                 {
932                 controlSocket = net_drivers[net_driverlevel].Init();
933                 if (controlSocket == -1)
934                         continue;
935                 net_drivers[net_driverlevel].initialized = true;
936                 net_drivers[net_driverlevel].controlSock = controlSocket;
937                 if (listening)
938                         net_drivers[net_driverlevel].Listen (true);
939                 }
940
941         if (*my_ipx_address)
942                 Con_DPrintf("IPX address %s\n", my_ipx_address);
943         if (*my_tcpip_address)
944                 Con_DPrintf("TCP/IP address %s\n", my_tcpip_address);
945
946         Master_Init ();
947 }
948
949 /*
950 ====================
951 NET_Shutdown
952 ====================
953 */
954
955 void NET_Shutdown (void)
956 {
957         SetNetTime();
958
959         while (net_activeSockets)
960                 NET_Close(net_activeSockets);
961
962 //
963 // shutdown the drivers
964 //
965         for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++)
966         {
967                 if (net_drivers[net_driverlevel].initialized == true)
968                 {
969                         net_drivers[net_driverlevel].Shutdown ();
970                         net_drivers[net_driverlevel].initialized = false;
971                 }
972         }
973
974         Mem_FreePool(&net_mempool);
975 }
976
977
978 static PollProcedure *pollProcedureList = NULL;
979
980 void NET_Poll(void)
981 {
982         PollProcedure *pp;
983
984         if (!configRestored)
985                 configRestored = true;
986
987         SetNetTime();
988
989         for (pp = pollProcedureList; pp; pp = pp->next)
990         {
991                 if (pp->nextTime > net_time)
992                         break;
993                 pollProcedureList = pp->next;
994                 pp->procedure(pp->arg);
995         }
996 }
997
998
999 void SchedulePollProcedure(PollProcedure *proc, double timeOffset)
1000 {
1001         PollProcedure *pp, *prev;
1002
1003         proc->nextTime = Sys_DoubleTime() + timeOffset;
1004         for (pp = pollProcedureList, prev = NULL; pp; pp = pp->next)
1005         {
1006                 if (pp->nextTime >= proc->nextTime)
1007                         break;
1008                 prev = pp;
1009         }
1010
1011         if (prev == NULL)
1012         {
1013                 proc->next = pollProcedureList;
1014                 pollProcedureList = proc;
1015                 return;
1016         }
1017
1018         proc->next = pp;
1019         prev->next = proc;
1020 }
1021