Thanks to Elric for adding dpmaster support!
authorhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Tue, 24 Sep 2002 12:16:28 +0000 (12:16 +0000)
committerhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Tue, 24 Sep 2002 12:16:28 +0000 (12:16 +0000)
slist command renamed to net_slist, net_inetslist command added
"heartbeat" command notifies master server(s) of your server's presence (this is automatic, but you can force a heartbeat)
sv_master1 through sv_master4 cvars contain master server addresses, they all default to "" (none), this may change if someone hosts a darkplaces master server and wants it added to the defaults...  (note: these cvars ARE saved to config)
com_modname contains the currently running mod directory name (for example id1, darkplaces, transfusion, etc)
some Con_DPrintf's have been added to the server query code, so if you want to know if people are checking out your server, it should tell you about it now (I think?)
some Con_DPrintf's exist in the inetslist code so you can watch the packet flow

git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@2432 d7cf8633-e32d-0410-b094-e92efae38249

23 files changed:
common.c
common.h
darkplaces.dsp
host.c
makefile
menu.c
net.h
net_bsd.c
net_dgrm.c
net_dgrm.h
net_loop.c
net_loop.h
net_main.c
net_master.c [new file with mode: 0644]
net_master.h [new file with mode: 0644]
net_udp.c
net_udp.h
net_win.c
net_wins.c
net_wins.h
net_wipx.c
net_wipx.h
sv_main.c

index af2161f..0f413b2 100644 (file)
--- a/common.c
+++ b/common.c
@@ -50,6 +50,7 @@ char com_cmdline[CMDLINE_LENGTH];
 int gamemode;
 char *gamename;
 char *gamedirname;
+char com_modname[MAX_OSPATH];
 
 /*
 
@@ -1425,10 +1426,12 @@ void COM_InitFilesystem (void)
                com_basedir[i-1] = 0;
 
 // start up with GAMENAME by default (id1)
+       strcpy(com_modname, GAMENAME);
        COM_AddGameDirectory (va("%s/"GAMENAME, com_basedir));
        if (gamedirname[0])
        {
                com_modified = true;
+               strcpy(com_modname, gamedirname);
                COM_AddGameDirectory (va("%s/%s", com_basedir, gamedirname));
        }
 
@@ -1438,6 +1441,7 @@ void COM_InitFilesystem (void)
        if (i && i < com_argc-1)
        {
                com_modified = true;
+               strcpy(com_modname, com_argv[i+1]);
                COM_AddGameDirectory (va("%s/%s", com_basedir, com_argv[i+1]));
        }
 
index 78b23a6..ce8b6ea 100644 (file)
--- a/common.h
+++ b/common.h
@@ -175,6 +175,7 @@ extern      struct cvar_s   registered;
 
 extern int gamemode;
 extern char *gamename;
+extern char com_modname[MAX_OSPATH];
 
 // LordHavoc: useful...
 void COM_ToLowerString(const char *in, char *out);
index 77ae9bd..b79f26a 100644 (file)
@@ -268,6 +268,10 @@ SOURCE=.\net_main.c
 # End Source File\r
 # Begin Source File\r
 \r
+SOURCE=.\net_master.c\r
+# End Source File\r
+# Begin Source File\r
+\r
 SOURCE=.\net_win.c\r
 # End Source File\r
 # Begin Source File\r
@@ -568,6 +572,10 @@ SOURCE=.\net_loop.h
 # End Source File\r
 # Begin Source File\r
 \r
+SOURCE=.\net_master.h\r
+# End Source File\r
+# Begin Source File\r
+\r
 SOURCE=.\net_wins.h\r
 # End Source File\r
 # Begin Source File\r
diff --git a/host.c b/host.c
index 9fcc9cf..42dca46 100644 (file)
--- a/host.c
+++ b/host.c
@@ -461,6 +461,8 @@ void SV_DropClient (qboolean crash)
                MSG_WriteByte (&client->message, host_client - svs.clients);
                MSG_WriteByte (&client->message, 0);
        }
+
+       NET_Heartbeat ();
 }
 
 /*
@@ -488,6 +490,9 @@ void Host_ShutdownServer(qboolean crash)
 // stop all client sounds immediately
        CL_Disconnect ();
 
+       NET_Heartbeat ();
+       NET_Heartbeat ();
+
 // flush any pending messages - like the score!!!
        start = Sys_DoubleTime();
        do
index 49c7edf..09a468c 100644 (file)
--- a/makefile
+++ b/makefile
@@ -24,7 +24,7 @@ CD=cd_null.o
 
 CLIENTOBJECTS= cgame.o cgamevm.o chase.o cl_collision.o cl_demo.o cl_input.o cl_main.o cl_parse.o cl_particles.o cl_screen.o cl_video.o console.o dpvsimpledecode.o fractalnoise.o gl_backend.o gl_draw.o gl_models.o gl_rmain.o gl_rsurf.o gl_textures.o keys.o menu.o meshqueue.o r_crosshairs.o r_explosion.o r_explosion.o r_lerpanim.o r_light.o r_modules.o r_sky.o r_sprites.o sbar.o ui.o vid_shared.o view.o wavefile.o
 SERVEROBJECTS= pr_cmds.o pr_edict.o pr_exec.o sv_light.o sv_main.o sv_move.o sv_phys.o sv_user.o
-SHAREDOBJECTS= builddate.o cmd.o collision.o common.o crc.o cvar.o filematch.o host.o host_cmd.o image.o mathlib.o matrixlib.o model_alias.o model_brush.o model_shared.o model_sprite.o net_bsd.o net_dgrm.o net_loop.o net_main.o net_udp.o palette.o portals.o protocol.o quakeio.o sys_linux.o sys_shared.o transform.o world.o wad.o zone.o $(NETOBJECTS) $(SERVEROBJECTS)
+SHAREDOBJECTS= builddate.o cmd.o collision.o common.o crc.o cvar.o filematch.o host.o host_cmd.o image.o mathlib.o matrixlib.o model_alias.o model_brush.o model_shared.o model_sprite.o net_bsd.o net_dgrm.o net_loop.o net_main.o net_master.o net_udp.o palette.o portals.o protocol.o quakeio.o sys_linux.o sys_shared.o transform.o world.o wad.o zone.o $(NETOBJECTS) $(SERVEROBJECTS)
 
 
 #K6/athlon optimizations
diff --git a/menu.c b/menu.c
index fe2097a..8af1550 100644 (file)
--- a/menu.c
+++ b/menu.c
@@ -46,6 +46,7 @@ void M_Menu_Main_f (void);
 void M_Menu_LanConfig_f (void);
 void M_Menu_GameOptions_f (void);
 void M_Menu_Search_f (void);
+void M_Menu_InetSearch_f (void);
 void M_Menu_ServerList_f (void);
 
 void M_Main_Draw (void);
@@ -64,6 +65,7 @@ void M_Main_Draw (void);
 void M_LanConfig_Draw (void);
 void M_GameOptions_Draw (void);
 void M_Search_Draw (void);
+void M_InetSearch_Draw (void);
 void M_ServerList_Draw (void);
 
 void M_Main_Key (int key);
@@ -82,6 +84,7 @@ void M_Main_Key (int key);
 void M_LanConfig_Key (int key);
 void M_GameOptions_Key (int key);
 void M_Search_Key (int key);
+void M_InetSearch_Key (int key);
 void M_ServerList_Key (int key);
 
 qboolean       m_entersound;           // play after drawing a frame, so caching
@@ -853,7 +856,7 @@ void M_MultiPlayer_Draw (void)
 
        if (ipxAvailable || tcpipAvailable)
                return;
-       M_PrintWhite ((320/2) - ((27*8)/2), 148, "No Communications Available");
+       M_PrintWhite ((320/2) - ((27*8)/2), 168, "No Communications Available");
 }
 
 
@@ -2148,8 +2151,8 @@ void M_Quit_Draw (void)
 /* LAN CONFIG MENU */
 
 int            lanConfig_cursor = -1;
-int            lanConfig_cursor_table [] = {72, 92, 124};
-#define NUM_LANCONFIG_CMDS     3
+int            lanConfig_cursor_table [] = {72, 92, 112, 144};
+#define NUM_LANCONFIG_CMDS     4
 
 int    lanConfig_port;
 char   lanConfig_portname[6];
@@ -2213,9 +2216,10 @@ void M_LanConfig_Draw (void)
        if (JoiningGame)
        {
                M_Print (basex, lanConfig_cursor_table[1], "Search for local games...");
-               M_Print (basex, 108, "Join game at:");
-               M_DrawTextBox (basex+8, lanConfig_cursor_table[2]-8, 22, 1);
-               M_Print (basex+16, lanConfig_cursor_table[2], lanConfig_joinname);
+               M_Print (basex, lanConfig_cursor_table[2], "Search for internet games...");
+               M_Print (basex, 128, "Join game at:");
+               M_DrawTextBox (basex+8, lanConfig_cursor_table[3]-8, 22, 1);
+               M_Print (basex+16, lanConfig_cursor_table[3], lanConfig_joinname);
        }
        else
        {
@@ -2228,11 +2232,11 @@ void M_LanConfig_Draw (void)
        if (lanConfig_cursor == 0)
                M_DrawCharacter (basex+9*8 + 8*strlen(lanConfig_portname), lanConfig_cursor_table [0], 10+((int)(realtime*4)&1));
 
-       if (lanConfig_cursor == 2)
-               M_DrawCharacter (basex+16 + 8*strlen(lanConfig_joinname), lanConfig_cursor_table [2], 10+((int)(realtime*4)&1));
+       if (lanConfig_cursor == 3)
+               M_DrawCharacter (basex+16 + 8*strlen(lanConfig_joinname), lanConfig_cursor_table [3], 10+((int)(realtime*4)&1));
 
        if (*m_return_reason)
-               M_PrintWhite (basex, 148, m_return_reason);
+               M_PrintWhite (basex, 168, m_return_reason);
 }
 
 
@@ -2268,18 +2272,21 @@ void M_LanConfig_Key (int key)
 
                M_ConfigureNetSubsystem ();
 
-               if (lanConfig_cursor == 1)
+               if (lanConfig_cursor == 1 || lanConfig_cursor == 2)
                {
                        if (StartingGame)
                        {
                                M_Menu_GameOptions_f ();
                                break;
                        }
-                       M_Menu_Search_f();
+                       if (lanConfig_cursor == 1)
+                               M_Menu_Search_f();
+                       else
+                               M_Menu_InetSearch_f();
                        break;
                }
 
-               if (lanConfig_cursor == 2)
+               if (lanConfig_cursor == 3)
                {
                        m_return_state = m_state;
                        m_return_onerror = true;
@@ -2298,7 +2305,7 @@ void M_LanConfig_Key (int key)
                                lanConfig_portname[strlen(lanConfig_portname)-1] = 0;
                }
 
-               if (lanConfig_cursor == 2)
+               if (lanConfig_cursor == 3)
                {
                        if (strlen(lanConfig_joinname))
                                lanConfig_joinname[strlen(lanConfig_joinname)-1] = 0;
@@ -2309,7 +2316,7 @@ void M_LanConfig_Key (int key)
                if (key < 32 || key > 127)
                        break;
 
-               if (lanConfig_cursor == 2)
+               if (lanConfig_cursor == 3)
                {
                        l = strlen(lanConfig_joinname);
                        if (l < 21)
@@ -2332,7 +2339,7 @@ void M_LanConfig_Key (int key)
                }
        }
 
-       if (StartingGame && lanConfig_cursor == 2)
+       if (StartingGame && lanConfig_cursor == 3)
        {
                if (key == K_UPARROW)
                        lanConfig_cursor = 1;
@@ -2993,6 +3000,63 @@ void M_Search_Key (int key)
 }
 
 //=============================================================================
+/* INTERNET SEARCH MENU */
+
+void M_Menu_InetSearch_f (void)
+{
+       key_dest = key_menu;
+       m_state = m_search;
+       m_entersound = false;
+       slistSilent = true;
+       slistLocal = false;
+       searchComplete = false;
+       NET_InetSlist_f();
+
+}
+
+
+void M_InetSearch_Draw (void)
+{
+       cachepic_t      *p;
+       int x;
+
+       p = Draw_CachePic ("gfx/p_multi.lmp");
+       M_DrawPic ( (320-p->width)/2, 4, "gfx/p_multi.lmp");
+       x = (320/2) - ((12*8)/2) + 4;
+       M_DrawTextBox (x-8, 32, 12, 1);
+       M_Print (x, 40, "Searching...");
+
+       if(slistInProgress)
+       {
+               NET_Poll();
+               return;
+       }
+
+       if (! searchComplete)
+       {
+               searchComplete = true;
+               searchCompleteTime = realtime;
+       }
+
+       if (hostCacheCount)
+       {
+               M_Menu_ServerList_f ();
+               return;
+       }
+
+       M_PrintWhite ((320/2) - ((22*8)/2), 64, "No Quake servers found");
+       if ((realtime - searchCompleteTime) < 3.0)
+               return;
+
+       M_Menu_LanConfig_f ();
+}
+
+
+void M_InetSearch_Key (int key)
+{
+}
+
+//=============================================================================
 /* SLIST MENU */
 
 int            slist_cursor;
@@ -3047,7 +3111,7 @@ void M_ServerList_Draw (void)
        M_DrawCharacter (0, 32 + slist_cursor*8, 12+((int)(realtime*4)&1));
 
        if (*m_return_reason)
-               M_PrintWhite (16, 148, m_return_reason);
+               M_PrintWhite (16, 168, m_return_reason);
 }
 
 
diff --git a/net.h b/net.h
index c111bf0..55800b0 100644 (file)
--- a/net.h
+++ b/net.h
@@ -165,6 +165,8 @@ typedef struct
        int             (*CloseSocket) (int socket);
        int             (*Connect) (int socket, struct qsockaddr *addr);
        int             (*CheckNewConnections) (void);
+       int             (*Recv) (qbyte *buf, int len, struct qsockaddr *addr);
+       int                     (*Send) (qbyte *buf, int len, struct qsockaddr *addr);
        int             (*Read) (int socket, qbyte *buf, int len, struct qsockaddr *addr);
        int             (*Write) (int socket, qbyte *buf, int len, struct qsockaddr *addr);
        int             (*Broadcast) (int socket, qbyte *buf, int len);
@@ -189,6 +191,7 @@ typedef struct
        int                     (*Init) (void);
        void            (*Listen) (qboolean state);
        void            (*SearchForHosts) (qboolean xmit);
+       qboolean        (*SearchForInetHosts) (char *master);
        qsocket_t       *(*Connect) (char *host);
        qsocket_t       *(*CheckNewConnections) (void);
        int                     (*QGetMessage) (qsocket_t *sock);
@@ -198,6 +201,7 @@ typedef struct
        qboolean        (*CanSendUnreliableMessage) (qsocket_t *sock);
        void            (*Close) (qsocket_t *sock);
        void            (*Shutdown) (void);
+       void            (*Heartbeat) (char *host);
        int                     controlSock;
 } net_driver_t;
 
@@ -273,6 +277,9 @@ struct qsocket_s    *NET_CheckNewConnections (void);
 struct qsocket_s       *NET_Connect (char *host);
 // called by client to connect to a host.  Returns -1 if not able to
 
+void           NET_Heartbeat (void);
+// Send an heartbeat to the master server(s)
+
 qboolean NET_CanSendMessage (qsocket_t *sock);
 // Returns true or false if the given qsocket can currently accept a
 // message to be transmitted.
@@ -329,6 +336,7 @@ extern      qboolean        slistLocal;
 extern cvar_t hostname;
 
 void NET_Slist_f (void);
+void NET_InetSlist_f (void);
 
 #endif
 
index 1713515..9b547d8 100644 (file)
--- a/net_bsd.c
+++ b/net_bsd.c
@@ -30,6 +30,7 @@ net_driver_t net_drivers[MAX_NET_DRIVERS] =
        Loop_Init,
        Loop_Listen,
        Loop_SearchForHosts,
+       Loop_SearchForInetHosts,
        Loop_Connect,
        Loop_CheckNewConnections,
        Loop_GetMessage,
@@ -38,7 +39,8 @@ net_driver_t net_drivers[MAX_NET_DRIVERS] =
        Loop_CanSendMessage,
        Loop_CanSendUnreliableMessage,
        Loop_Close,
-       Loop_Shutdown
+       Loop_Shutdown,
+       Loop_Heartbeat
        }
        ,
        {
@@ -47,6 +49,7 @@ net_driver_t net_drivers[MAX_NET_DRIVERS] =
        Datagram_Init,
        Datagram_Listen,
        Datagram_SearchForHosts,
+       Datagram_SearchForInetHosts,
        Datagram_Connect,
        Datagram_CheckNewConnections,
        Datagram_GetMessage,
@@ -55,7 +58,8 @@ net_driver_t net_drivers[MAX_NET_DRIVERS] =
        Datagram_CanSendMessage,
        Datagram_CanSendUnreliableMessage,
        Datagram_Close,
-       Datagram_Shutdown
+       Datagram_Shutdown,
+       Datagram_Heartbeat
        }
 };
 
@@ -76,6 +80,8 @@ net_landriver_t       net_landrivers[MAX_NET_DRIVERS] =
        UDP_CloseSocket,
        UDP_Connect,
        UDP_CheckNewConnections,
+       UDP_Recv,
+       UDP_Send,
        UDP_Read,
        UDP_Write,
        UDP_Broadcast,
index 20f06c5..66ec880 100644 (file)
@@ -54,6 +54,7 @@ unsigned long inet_addr(const char *cp);
 
 #include "quakedef.h"
 #include "net_dgrm.h"
+#include "net_master.h"
 
 cvar_t cl_port = {CVAR_SAVE, "cl_port", "0"};
 
@@ -847,8 +848,18 @@ static qsocket_t *_Datagram_CheckNewConnections (void)
        MSG_BeginReading ();
        control = BigLong(*((int *)net_message.data));
        MSG_ReadLong();
-       if (control == -1)
+       
+       // Messages starting by 0xFFFFFFFF are master server messages
+       if (control == 0xFFFFFFFF)
+       {
+               int responsesize = Master_HandleMessage();
+               if (responsesize > 0)
+               {
+                       dfunc.Write(acceptsock, net_message.data, responsesize, &clientaddr);
+                       SZ_Clear(&net_message);
+               }
                return NULL;
+       }
        if ((control & (~NETFLAG_LENGTH_MASK)) !=  NETFLAG_CTL)
                return NULL;
        if ((control & NETFLAG_LENGTH_MASK) != len)
@@ -860,6 +871,8 @@ static qsocket_t *_Datagram_CheckNewConnections (void)
                if (strcmp(MSG_ReadString(), "QUAKE") != 0)
                        return NULL;
 
+               Con_DPrintf("Datagram_CheckNewConnections: received CCREQ_SERVERINFO, replying.\n");
+
                SZ_Clear(&net_message);
                // save space for the header, filled in later
                MSG_WriteLong(&net_message, 0);
@@ -1077,17 +1090,95 @@ qsocket_t *Datagram_CheckNewConnections (void)
 }
 
 
+static qboolean Datagram_HandleServerInfo (struct qsockaddr *readaddr)
+{
+       struct qsockaddr myaddr;
+       int control;
+       int c, n, i;
+
+       if (net_message.cursize < sizeof(int))
+               return false;
+
+       // don't answer our own query
+       dfunc.GetSocketAddr (dfunc.controlSock, &myaddr);
+       //if (dfunc.AddrCompare(readaddr, &myaddr) >= 0)
+       //      return false;
+
+       // is the cache full?
+       if (hostCacheCount == HOSTCACHESIZE)
+               return false;
+
+       MSG_BeginReading ();
+       control = BigLong(*((int *)net_message.data));
+       MSG_ReadLong();
+       if (control == -1)
+               return false;
+       if ((control & (~NETFLAG_LENGTH_MASK)) !=  NETFLAG_CTL)
+               return false;
+       if ((control & NETFLAG_LENGTH_MASK) != net_message.cursize)
+               return false;
+
+       c = MSG_ReadByte();
+       if (c != CCREP_SERVER_INFO)
+               return false;
+
+       dfunc.GetAddrFromName(MSG_ReadString(), readaddr);
+       // search the cache for this server
+       for (n = 0; n < hostCacheCount; n++)
+               if (dfunc.AddrCompare(readaddr, &hostcache[n].addr) == 0)
+                       break;
+
+       // is it already there?
+       if (n < hostCacheCount)
+               return false;;
+
+       // add it
+       hostCacheCount++;
+       strcpy(hostcache[n].name, MSG_ReadString());
+       strcpy(hostcache[n].map, MSG_ReadString());
+       hostcache[n].users = MSG_ReadByte();
+       hostcache[n].maxusers = MSG_ReadByte();
+       c = MSG_ReadByte();
+       if (c != NET_PROTOCOL_VERSION)
+       {
+               strcpy(hostcache[n].cname, hostcache[n].name);
+               hostcache[n].cname[14] = 0;
+               strcpy(hostcache[n].name, "*");
+               strcat(hostcache[n].name, hostcache[n].cname);
+       }
+       memcpy(&hostcache[n].addr, readaddr, sizeof(struct qsockaddr));
+       hostcache[n].driver = net_driverlevel;
+       hostcache[n].ldriver = net_landriverlevel;
+       strcpy(hostcache[n].cname, dfunc.AddrToString(readaddr));
+
+       // check for a name conflict
+       for (i = 0; i < hostCacheCount; i++)
+       {
+               if (i == n)
+                       continue;
+               if (Q_strcasecmp (hostcache[n].name, hostcache[i].name) == 0)
+               {
+                       i = strlen(hostcache[n].name);
+                       if (i < 15 && hostcache[n].name[i-1] > '8')
+                       {
+                               hostcache[n].name[i] = '0';
+                               hostcache[n].name[i+1] = 0;
+                       }
+                       else
+                               hostcache[n].name[i-1]++;
+                       i = -1;
+               }
+       }
+
+       return true;
+}
+
+
 static void _Datagram_SearchForHosts (qboolean xmit)
 {
        int             ret;
-       int             n;
-       int             i;
        struct qsockaddr readaddr;
-       struct qsockaddr myaddr;
-       int             control;
-       int             c;
 
-       dfunc.GetSocketAddr (dfunc.controlSock, &myaddr);
        if (xmit)
        {
                SZ_Clear(&net_message);
@@ -1103,91 +1194,78 @@ static void _Datagram_SearchForHosts (qboolean xmit)
 
        while ((ret = dfunc.Read (dfunc.controlSock, net_message.data, net_message.maxsize, &readaddr)) > 0)
        {
-               if (ret < sizeof(int))
-                       continue;
                net_message.cursize = ret;
+               Datagram_HandleServerInfo (&readaddr);
+       }
+}
 
-               // don't answer our own query
-               if (dfunc.AddrCompare(&readaddr, &myaddr) >= 0)
-                       continue;
-
-               // is the cache full?
+void Datagram_SearchForHosts (qboolean xmit)
+{
+       for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
+       {
                if (hostCacheCount == HOSTCACHESIZE)
-                       continue;
-
-               MSG_BeginReading ();
-               control = BigLong(*((int *)net_message.data));
-               MSG_ReadLong();
-               if (control == -1)
-                       continue;
-               if ((control & (~NETFLAG_LENGTH_MASK)) !=  NETFLAG_CTL)
-                       continue;
-               if ((control & NETFLAG_LENGTH_MASK) != ret)
-                       continue;
-
-               c = MSG_ReadByte();
-               if (c != CCREP_SERVER_INFO)
-                       continue;
+                       break;
+               if (net_landrivers[net_landriverlevel].initialized)
+                       _Datagram_SearchForHosts (xmit);
+       }
+}
 
-               dfunc.GetAddrFromName(MSG_ReadString(), &readaddr);
-               // search the cache for this server
-               for (n = 0; n < hostCacheCount; n++)
-                       if (dfunc.AddrCompare(&readaddr, &hostcache[n].addr) == 0)
-                               break;
 
-               // is it already there?
-               if (n < hostCacheCount)
-                       continue;
+static qboolean _Datagram_SearchForInetHosts (char *master)
+{
+       qboolean result = false;
+       struct qsockaddr masteraddr;
+       struct qsockaddr readaddr;
+       int ret;
 
-               // add it
-               hostCacheCount++;
-               strcpy(hostcache[n].name, MSG_ReadString());
-               strcpy(hostcache[n].map, MSG_ReadString());
-               hostcache[n].users = MSG_ReadByte();
-               hostcache[n].maxusers = MSG_ReadByte();
-               c = MSG_ReadByte();
-               if (c != NET_PROTOCOL_VERSION)
+       if (master)
+       {
+               if (dfunc.GetAddrFromName(master, &masteraddr) != -1)
                {
-                       strcpy(hostcache[n].cname, hostcache[n].name);
-                       hostcache[n].cname[14] = 0;
-                       strcpy(hostcache[n].name, "*");
-                       strcat(hostcache[n].name, hostcache[n].cname);
+                       int portnum = 0;
+                       const char* port = strrchr (master, ':');
+                       if (port)
+                               portnum = atoi (port + 1);
+                       if (!portnum)
+                               portnum = MASTER_PORT;
+                       Con_DPrintf("Datagram_SearchForInetHosts: sending %d byte message to master %s\n", net_message.cursize, master);
+                       dfunc.SetSocketPort (&masteraddr, portnum);
+                       dfunc.Send (net_message.data, net_message.cursize, &masteraddr);
                }
-               memcpy(&hostcache[n].addr, &readaddr, sizeof(struct qsockaddr));
-               hostcache[n].driver = net_driverlevel;
-               hostcache[n].ldriver = net_landriverlevel;
-               strcpy(hostcache[n].cname, dfunc.AddrToString(&readaddr));
+       }
 
-               // check for a name conflict
-               for (i = 0; i < hostCacheCount; i++)
-               {
-                       if (i == n)
-                               continue;
-                       if (Q_strcasecmp (hostcache[n].name, hostcache[i].name) == 0)
-                       {
-                               i = strlen(hostcache[n].name);
-                               if (i < 15 && hostcache[n].name[i-1] > '8')
-                               {
-                                       hostcache[n].name[i] = '0';
-                                       hostcache[n].name[i+1] = 0;
-                               }
-                               else
-                                       hostcache[n].name[i-1]++;
-                               i = -1;
-                       }
-               }
+       while ((ret = dfunc.Recv (net_message.data, net_message.maxsize, &readaddr)) > 0)
+       {
+               net_message.cursize = ret;
+               Con_DPrintf("Datagram_SearchForInetHosts: Recv received %d byte message\n", net_message.cursize);
+               Master_ParseServerList (&dfunc);
        }
+       
+       while ((ret = dfunc.Read (dfunc.controlSock, net_message.data, net_message.maxsize, &readaddr)) > 0)
+       {
+               net_message.cursize = ret;
+               Con_DPrintf("Datagram_SearchForInetHosts: Read received %d byte message\n", net_message.cursize);
+               if (Datagram_HandleServerInfo (&readaddr))
+                       result = true;
+       }
+
+       return result;
 }
 
-void Datagram_SearchForHosts (qboolean xmit)
+
+qboolean Datagram_SearchForInetHosts (char *master)
 {
+       qboolean result = false;
        for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
        {
                if (hostCacheCount == HOSTCACHESIZE)
                        break;
                if (net_landrivers[net_landriverlevel].initialized)
-                       _Datagram_SearchForHosts (xmit);
+                       if (_Datagram_SearchForInetHosts (master))
+                               result = true;
        }
+       
+       return result;
 }
 
 
@@ -1367,3 +1445,29 @@ qsocket_t *Datagram_Connect (char *host)
        return ret;
 }
 
+static void _Datagram_Heartbeat (char *master)
+{
+       struct qsockaddr masteraddr;
+       int portnum;
+       const char* port;
+
+       if (dfunc.GetAddrFromName(master, &masteraddr) == -1)
+               return;
+
+       portnum = 0;
+       port = strrchr (master, ':');
+       if (port)
+               portnum = atoi (port + 1);
+       if (!portnum)
+               portnum = MASTER_PORT;
+       dfunc.SetSocketPort (&masteraddr, portnum);
+
+       dfunc.Send (net_message.data, net_message.cursize, &masteraddr);
+}
+
+void Datagram_Heartbeat (char *master)
+{
+       for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
+               if (net_landrivers[net_landriverlevel].initialized)
+                       _Datagram_Heartbeat (master);
+}
index af40139..da3f28b 100644 (file)
@@ -25,6 +25,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 int                    Datagram_Init (void);
 void           Datagram_Listen (qboolean state);
 void           Datagram_SearchForHosts (qboolean xmit);
+qboolean       Datagram_SearchForInetHosts (char *master);
 qsocket_t      *Datagram_Connect (char *host);
 qsocket_t      *Datagram_CheckNewConnections (void);
 int                    Datagram_GetMessage (qsocket_t *sock);
@@ -34,6 +35,7 @@ qboolean      Datagram_CanSendMessage (qsocket_t *sock);
 qboolean       Datagram_CanSendUnreliableMessage (qsocket_t *sock);
 void           Datagram_Close (qsocket_t *sock);
 void           Datagram_Shutdown (void);
+void           Datagram_Heartbeat (char *master);
 
 #endif
 
index bfb356b..0cd6662 100644 (file)
@@ -39,6 +39,11 @@ void Loop_Shutdown (void)
 }
 
 
+void Loop_Heartbeat (char *master)
+{
+}
+
+
 void Loop_Listen (qboolean state)
 {
 }
@@ -62,6 +67,12 @@ void Loop_SearchForHosts (qboolean xmit)
 }
 
 
+qboolean Loop_SearchForInetHosts (char *master)
+{
+       return false;
+}
+
+
 qsocket_t *Loop_Connect (char *host)
 {
        if (strcmp(host,"local") != 0)
index 4f248f4..2d62a6c 100644 (file)
@@ -25,6 +25,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 int                    Loop_Init (void);
 void           Loop_Listen (qboolean state);
 void           Loop_SearchForHosts (qboolean xmit);
+qboolean       Loop_SearchForInetHosts (char *master);
 qsocket_t      *Loop_Connect (char *host);
 qsocket_t      *Loop_CheckNewConnections (void);
 int                    Loop_GetMessage (qsocket_t *sock);
@@ -34,6 +35,7 @@ qboolean      Loop_CanSendMessage (qsocket_t *sock);
 qboolean       Loop_CanSendUnreliableMessage (qsocket_t *sock);
 void           Loop_Close (qsocket_t *sock);
 void           Loop_Shutdown (void);
+void           Loop_Heartbeat (char *master);
 
 #endif
 
index a7137ab..ed2d341 100644 (file)
@@ -20,6 +20,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 // net_main.c
 
 #include "quakedef.h"
+#include "net_master.h"
 
 qsocket_t *net_activeSockets = NULL;
 mempool_t *net_mempool;
@@ -46,6 +47,11 @@ static void Slist_Poll(void);
 PollProcedure  slistSendProcedure = {NULL, 0.0, Slist_Send};
 PollProcedure  slistPollProcedure = {NULL, 0.0, Slist_Poll};
 
+static void InetSlist_Send(void);
+static void InetSlist_Poll(void);
+PollProcedure  inetSlistSendProcedure = {NULL, 0.0, InetSlist_Send};
+PollProcedure  inetSlistPollProcedure = {NULL, 0.0, InetSlist_Poll};
+
 
 sizebuf_t              net_message;
 int                            net_activeconnections = 0;
@@ -220,6 +226,12 @@ static void NET_Port_f (void)
 }
 
 
+static void NET_Heartbeat_f (void)
+{
+       NET_Heartbeat ();
+}
+
+
 static void PrintSlistHeader(void)
 {
        Con_Printf("Server          Map             Users\n");
@@ -273,6 +285,27 @@ void NET_Slist_f (void)
 }
 
 
+void NET_InetSlist_f (void)
+{
+       if (slistInProgress)
+               return;
+
+       if (! slistSilent)
+       {
+               Con_Printf("Looking for Quake servers...\n");
+               PrintSlistHeader();
+       }
+
+       slistInProgress = true;
+       slistStartTime = Sys_DoubleTime();
+
+       SchedulePollProcedure(&inetSlistSendProcedure, 0.0);
+       SchedulePollProcedure(&inetSlistPollProcedure, 0.1);
+
+       hostCacheCount = 0;
+}
+
+
 static void Slist_Send(void)
 {
        for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
@@ -317,6 +350,60 @@ static void Slist_Poll(void)
 }
 
 
+static void InetSlist_Send(void)
+{
+       char* host;
+
+       if (!slistInProgress)
+               return;
+
+       while ((host = Master_BuildGetServers ()) != NULL)
+       {
+               for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
+               {
+                       if (!slistLocal && net_driverlevel == 0)
+                               continue;
+                       if (net_drivers[net_driverlevel].initialized == false)
+                               continue;
+                       dfunc.SearchForInetHosts (host);
+               }
+       }
+
+       if ((Sys_DoubleTime() - slistStartTime) < 3.5)
+               SchedulePollProcedure(&inetSlistSendProcedure, 1.0);
+}
+
+
+static void InetSlist_Poll(void)
+{
+       for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
+       {
+               if (!slistLocal && net_driverlevel == 0)
+                       continue;
+               if (net_drivers[net_driverlevel].initialized == false)
+                       continue;
+               // We stop as soon as we have one answer (FIXME: bad...)
+               if (dfunc.SearchForInetHosts (NULL))
+                       slistInProgress = false;
+       }
+
+       if (! slistSilent)
+               PrintSlist();
+
+       if (slistInProgress && (Sys_DoubleTime() - slistStartTime) < 4.0)
+       {
+               SchedulePollProcedure(&inetSlistPollProcedure, 0.1);
+               return;
+       }
+
+       if (! slistSilent)
+               PrintSlistTrailer();
+       slistInProgress = false;
+       slistSilent = false;
+       slistLocal = true;
+}
+
+
 /*
 ===================
 NET_Connect
@@ -589,6 +676,30 @@ qboolean NET_CanSendMessage (qsocket_t *sock)
 }
 
 
+/*
+====================
+NET_Heartbeat
+
+Send an heartbeat to the master server(s)
+====================
+*/
+void NET_Heartbeat (void)
+{
+       char* host;
+       while ((host = Master_BuildHeartbeat ()) != NULL)
+       {
+               for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
+               {
+                       if (net_drivers[net_driverlevel].initialized == false)
+                               continue;
+                       if (net_driverlevel && listening == false)
+                               continue;
+                       dfunc.Heartbeat (host);
+               }
+       }
+}
+
+
 int NET_SendToAll(sizebuf_t *data, int blocktime)
 {
        double          start;
@@ -704,10 +815,12 @@ void NET_Init (void)
        Cvar_RegisterVariable (&net_messagetimeout);
        Cvar_RegisterVariable (&hostname);
 
-       Cmd_AddCommand ("slist", NET_Slist_f);
+       Cmd_AddCommand ("net_slist", NET_Slist_f);
+       Cmd_AddCommand ("net_inetslist", NET_InetSlist_f);
        Cmd_AddCommand ("listen", NET_Listen_f);
        Cmd_AddCommand ("maxplayers", MaxPlayers_f);
        Cmd_AddCommand ("port", NET_Port_f);
+       Cmd_AddCommand ("heartbeat", NET_Heartbeat_f);
 
        // initialize all the drivers
        for (net_driverlevel=0 ; net_driverlevel<net_numdrivers ; net_driverlevel++)
@@ -725,6 +838,8 @@ void NET_Init (void)
                Con_DPrintf("IPX address %s\n", my_ipx_address);
        if (*my_tcpip_address)
                Con_DPrintf("TCP/IP address %s\n", my_tcpip_address);
+
+       Master_Init ();
 }
 
 /*
diff --git a/net_master.c b/net_master.c
new file mode 100644 (file)
index 0000000..8fd7ed8
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+Copyright (C) 2002 Mathieu Olivier
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// net_master.c
+
+#include <malloc.h>
+#include "quakedef.h"
+
+cvar_t sv_masters [] =
+{
+       {CVAR_SAVE, "sv_master1", ""},
+       {CVAR_SAVE, "sv_master2", ""},
+       {CVAR_SAVE, "sv_master3", ""},
+       {CVAR_SAVE, "sv_master4", ""}
+};
+
+
+/*
+====================
+Master_BuildGetServers
+
+Build a getservers request for a master server
+====================
+*/
+char* Master_BuildGetServers (void)
+{
+       static int nextmaster = 0;
+       cvar_t* sv_master;
+       char request [256];
+       
+       if (nextmaster >= sizeof (sv_masters) / sizeof (sv_masters[0]))
+       {
+               nextmaster = 0;
+               return NULL;
+       }
+
+       sv_master = &sv_masters[nextmaster++];
+
+       // No master, no heartbeat
+       if (sv_master->string[0] == '\0')
+       {
+               nextmaster = 0;
+               return NULL;
+       }
+       
+       // Build the heartbeat
+       snprintf (request, sizeof (request), "getservers %s %u empty full\x0A", gamename, NET_PROTOCOL_VERSION);
+       SZ_Clear (&net_message);
+       MSG_WriteLong (&net_message, -1);
+       MSG_WriteString (&net_message, request);
+
+       net_message.cursize--;  // we don't send the trailing '\0'
+
+       return sv_master->string;
+}
+
+
+/*
+====================
+Master_BuildHeartbeat
+
+Build an heartbeat for a master server
+====================
+*/
+char* Master_BuildHeartbeat (void)
+{
+       static int nextmaster = 0;
+       cvar_t* sv_master;
+       
+       if (nextmaster >= sizeof (sv_masters) / sizeof (sv_masters[0]))
+       {
+               nextmaster = 0;
+               return NULL;
+       }
+
+       sv_master = &sv_masters[nextmaster++];
+
+       // No master, no heartbeat
+       if (sv_master->string[0] == '\0')
+       {
+               nextmaster = 0;
+               return NULL;
+       }
+       
+       // Build the heartbeat
+       SZ_Clear (&net_message);
+       MSG_WriteLong (&net_message, -1);
+       MSG_WriteString (&net_message, "heartbeat DarkPlaces\x0A");
+
+       net_message.cursize--;  // we don't send the trailing '\0'
+
+       return sv_master->string;
+}
+
+
+/*
+====================
+Master_HandleMessage
+
+Handle the master server messages
+====================
+*/
+int Master_HandleMessage (void)
+{
+       const char* string = MSG_ReadString ();
+
+       // If it's a "getinfo" request
+       if (!strncmp (string, "getinfo", 7))
+       {
+               char response [512];
+               size_t length;
+
+               length = snprintf (response, sizeof (response), "infoResponse\x0A"
+                                       "\\gamename\\%s\\modname\\%s\\sv_maxclients\\%d"
+                                       "\\clients\\%d\\mapname\\%s\\hostname\\%s\\protocol\\%d",
+                                       gamename, com_modname, svs.maxclients, net_activeconnections,
+                                       sv.name, hostname.string, NET_PROTOCOL_VERSION);
+
+               // Too long to fit into the buffer?
+               if (length >= sizeof (response))
+                       return -1;
+
+               // If there was a challenge in the getinfo message
+               if (string[7] == ' ')
+               {
+                       string += 8;  // skip the header and the space
+
+                       // If the challenge wouldn't fit into the buffer
+                       if (length + 11 + strlen (string) >= sizeof (response))
+                               return -1;
+
+                       sprintf (response + length, "\\challenge\\%s", string);
+               }
+
+               SZ_Clear (&net_message);
+               MSG_WriteLong (&net_message, -1);
+               MSG_WriteString (&net_message, response);
+
+               return net_message.cursize - 1;
+       }
+
+       return 0;
+}
+
+
+/*
+====================
+Master_Init
+
+Initialize the code that handles master server requests and reponses
+====================
+*/
+void Master_Init (void)
+{
+       unsigned int ind;
+       for (ind = 0; ind < sizeof (sv_masters) / sizeof (sv_masters[0]); ind++)
+               Cvar_RegisterVariable (&sv_masters[ind]);
+}
+
+
+/*
+====================
+Master_ParseServerList
+
+Parse getserverResponse messages
+====================
+*/
+void Master_ParseServerList (net_landriver_t* dfunc)
+{
+       int control;
+       qbyte* servers;
+       int ipaddr;
+       struct qsockaddr svaddr;
+       char ipstring [32];
+
+       if (net_message.cursize < sizeof(int))
+               return;
+
+       // is the cache full?
+       if (hostCacheCount == HOSTCACHESIZE)
+               return;
+
+       MSG_BeginReading ();
+       control = BigLong(*((int *)net_message.data));
+       MSG_ReadLong();
+       if (control != -1)
+               return;
+
+       if (strncmp (net_message.data + 4, "getserversResponse\\", 19)) 
+               return;
+
+       // Skip the next 18 bytes
+       MSG_ReadLong(); MSG_ReadLong(); MSG_ReadLong(); MSG_ReadLong();
+       MSG_ReadShort(); MSG_ReadByte();
+
+       servers = alloca (net_message.cursize - 23);
+       memcpy (servers , net_message.data + 23, net_message.cursize - 23);
+
+       // Extract the IP addresses
+       while ((ipaddr = (servers[3] << 24) + (servers[2] << 16) + (servers[1] << 8) + servers[0]) != -1)
+       {
+               int port = (servers[5] << 8) + servers[4];
+
+               if (port == -1 || port == 0)
+                       break;
+
+               port = ((port >> 8) & 0xFF) + ((port & 0xFF) << 8);
+               sprintf (ipstring, "%u.%u.%u.%u:%hu",
+                                       ipaddr & 0xFF, (ipaddr >> 8) & 0xFF,
+                                       (ipaddr >> 16) & 0xFF, ipaddr >> 24,
+                                       port);
+               dfunc->GetAddrFromName (ipstring, &svaddr);
+
+               Con_DPrintf("Requesting info from server %s\n", ipstring);
+               // Send a request at this address
+               SZ_Clear(&net_message);
+               MSG_WriteLong(&net_message, 0);  // save space for the header, filled in later
+               MSG_WriteByte(&net_message, CCREQ_SERVER_INFO);
+               MSG_WriteString(&net_message, "QUAKE");
+               MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION);
+               *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
+               dfunc->Write(dfunc->controlSock, net_message.data, net_message.cursize, &svaddr);
+               SZ_Clear(&net_message);
+
+               if (servers[6] != '\\')
+                       break;
+               servers += 7;
+       }
+}
diff --git a/net_master.h b/net_master.h
new file mode 100644 (file)
index 0000000..9325712
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+Copyright (C) 2002 Mathieu Olivier
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+
+See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+// net_master.h
+
+#ifndef NET_MASTER_H
+#define NET_MASTER_H
+
+#define MASTER_PORT 27950
+
+char* Master_BuildGetServers (void);
+char* Master_BuildHeartbeat (void);
+int Master_HandleMessage (void);
+void Master_Init (void);
+void Master_ParseServerList (net_landriver_t* dfunc);
+
+#endif
index b776298..2ec8e9c 100644 (file)
--- a/net_udp.c
+++ b/net_udp.c
@@ -244,6 +244,20 @@ int UDP_CheckNewConnections (void)
 
 //=============================================================================
 
+int UDP_Recv (qbyte *buf, int len, struct qsockaddr *addr)
+{
+       return UDP_Read (net_acceptsocket, buf, len, addr);
+}
+
+//=============================================================================
+
+int UDP_Send (qbyte *buf, int len, struct qsockaddr *addr)
+{
+       return UDP_Write (net_acceptsocket, buf, len, addr);
+}
+
+//=============================================================================
+
 int UDP_Read (int socket, qbyte *buf, int len, struct qsockaddr *addr)
 {
        int addrlen = sizeof (struct qsockaddr);
index 06b531b..1210e72 100644 (file)
--- a/net_udp.h
+++ b/net_udp.h
@@ -29,6 +29,8 @@ int  UDP_OpenSocket (int port);
 int  UDP_CloseSocket (int socket);
 int  UDP_Connect (int socket, struct qsockaddr *addr);
 int  UDP_CheckNewConnections (void);
+int  UDP_Recv (qbyte *buf, int len, struct qsockaddr *addr);
+int  UDP_Send (qbyte *buf, int len, struct qsockaddr *addr);
 int  UDP_Read (int socket, qbyte *buf, int len, struct qsockaddr *addr);
 int  UDP_Write (int socket, qbyte *buf, int len, struct qsockaddr *addr);
 int  UDP_Broadcast (int socket, qbyte *buf, int len);
index d34348c..725eef4 100644 (file)
--- a/net_win.c
+++ b/net_win.c
@@ -30,6 +30,7 @@ net_driver_t net_drivers[MAX_NET_DRIVERS] =
        Loop_Init,
        Loop_Listen,
        Loop_SearchForHosts,
+       Loop_SearchForInetHosts,
        Loop_Connect,
        Loop_CheckNewConnections,
        Loop_GetMessage,
@@ -47,6 +48,7 @@ net_driver_t net_drivers[MAX_NET_DRIVERS] =
        Datagram_Init,
        Datagram_Listen,
        Datagram_SearchForHosts,
+       Datagram_SearchForInetHosts,
        Datagram_Connect,
        Datagram_CheckNewConnections,
        Datagram_GetMessage,
@@ -78,6 +80,8 @@ net_landriver_t       net_landrivers[MAX_NET_DRIVERS] =
        WINS_CloseSocket,
        WINS_Connect,
        WINS_CheckNewConnections,
+       WINS_Recv,
+       WINS_Send,
        WINS_Read,
        WINS_Write,
        WINS_Broadcast,
@@ -101,6 +105,8 @@ net_landriver_t     net_landrivers[MAX_NET_DRIVERS] =
        WIPX_CloseSocket,
        WIPX_Connect,
        WIPX_CheckNewConnections,
+       WIPX_Recv,
+       WIPX_Send,
        WIPX_Read,
        WIPX_Write,
        WIPX_Broadcast,
index 5a12f52..16c1eb7 100644 (file)
@@ -392,6 +392,20 @@ int WINS_CheckNewConnections (void)
 
 //=============================================================================
 
+int WINS_Recv (qbyte *buf, int len, struct qsockaddr *addr)
+{
+       return WINS_Read (net_acceptsocket, buf, len, addr);
+}
+
+//=============================================================================
+
+int WINS_Send (qbyte *buf, int len, struct qsockaddr *addr)
+{
+       return WINS_Write (net_acceptsocket, buf, len, addr);
+}
+
+//=============================================================================
+
 int WINS_Read (int socket, qbyte *buf, int len, struct qsockaddr *addr)
 {
        int addrlen = sizeof (struct qsockaddr);
index a90da5b..7f401ab 100644 (file)
@@ -29,6 +29,8 @@ int  WINS_OpenSocket (int port);
 int  WINS_CloseSocket (int socket);
 int  WINS_Connect (int socket, struct qsockaddr *addr);
 int  WINS_CheckNewConnections (void);
+int  WINS_Recv (qbyte *buf, int len, struct qsockaddr *addr);
+int  WINS_Send (qbyte *buf, int len, struct qsockaddr *addr);
 int  WINS_Read (int socket, qbyte *buf, int len, struct qsockaddr *addr);
 int  WINS_Write (int socket, qbyte *buf, int len, struct qsockaddr *addr);
 int  WINS_Broadcast (int socket, qbyte *buf, int len);
index f1d2123..3e62cb4 100644 (file)
@@ -230,6 +230,20 @@ int WIPX_CheckNewConnections (void)
 
 //=============================================================================
 
+int WIPX_Recv (qbyte *buf, int len, struct qsockaddr *addr)
+{
+       return WIPX_Read (net_acceptsocket, buf, len, addr);
+}
+
+//=============================================================================
+
+int WIPX_Send (qbyte *buf, int len, struct qsockaddr *addr)
+{
+       return WIPX_Write (net_acceptsocket, buf, len, addr);
+}
+
+//=============================================================================
+
 static qbyte packetBuffer[NET_DATAGRAMSIZE + 4];
 
 int WIPX_Read (int handle, qbyte *buf, int len, struct qsockaddr *addr)
index b8caf43..120b2ab 100644 (file)
@@ -29,6 +29,8 @@ int  WIPX_OpenSocket (int port);
 int  WIPX_CloseSocket (int socket);
 int  WIPX_Connect (int socket, struct qsockaddr *addr);
 int  WIPX_CheckNewConnections (void);
+int  WIPX_Recv (qbyte *buf, int len, struct qsockaddr *addr);
+int  WIPX_Send (qbyte *buf, int len, struct qsockaddr *addr);
 int  WIPX_Read (int socket, qbyte *buf, int len, struct qsockaddr *addr);
 int  WIPX_Write (int socket, qbyte *buf, int len, struct qsockaddr *addr);
 int  WIPX_Broadcast (int socket, qbyte *buf, int len);
index 17f5f50..9dd462f 100644 (file)
--- a/sv_main.c
+++ b/sv_main.c
@@ -383,6 +383,7 @@ void SV_CheckForNewClients (void)
                SV_ConnectClient (i);
 
                net_activeconnections++;
+               NET_Heartbeat ();
        }
 }
 
@@ -1842,5 +1843,6 @@ void SV_SpawnServer (const char *server)
                        SV_SendServerinfo (host_client);
 
        Con_DPrintf ("Server spawned.\n");
+       NET_Heartbeat ();
 }