From: havoc Date: Tue, 24 Sep 2002 12:16:28 +0000 (+0000) Subject: Thanks to Elric for adding dpmaster support! X-Git-Tag: RELEASE_0_2_0_RC1~205 X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=04826446c325116c03990a9faf04d6439816a6e2;p=xonotic%2Fdarkplaces.git Thanks to Elric for adding dpmaster support! 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 --- diff --git a/common.c b/common.c index af2161f5..0f413b2d 100644 --- 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])); } diff --git a/common.h b/common.h index 78b23a6a..ce8b6eaf 100644 --- 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); diff --git a/darkplaces.dsp b/darkplaces.dsp index 77ae9bd0..b79f26a2 100644 --- a/darkplaces.dsp +++ b/darkplaces.dsp @@ -268,6 +268,10 @@ SOURCE=.\net_main.c # End Source File # Begin Source File +SOURCE=.\net_master.c +# End Source File +# Begin Source File + SOURCE=.\net_win.c # End Source File # Begin Source File @@ -568,6 +572,10 @@ SOURCE=.\net_loop.h # End Source File # Begin Source File +SOURCE=.\net_master.h +# End Source File +# Begin Source File + SOURCE=.\net_wins.h # End Source File # Begin Source File diff --git a/host.c b/host.c index 9fcc9cf8..42dca46c 100644 --- 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 diff --git a/makefile b/makefile index 49c7edf7..09a468c9 100644 --- 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 fe2097a9..8af1550f 100644 --- 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; @@ -2992,6 +2999,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 */ @@ -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 c111bf0e..55800b04 100644 --- 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 diff --git a/net_bsd.c b/net_bsd.c index 17135155..9b547d83 100644 --- 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, diff --git a/net_dgrm.c b/net_dgrm.c index 20f06c58..66ec880d 100644 --- a/net_dgrm.c +++ b/net_dgrm.c @@ -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); +} diff --git a/net_dgrm.h b/net_dgrm.h index af401392..da3f28bc 100644 --- a/net_dgrm.h +++ b/net_dgrm.h @@ -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 diff --git a/net_loop.c b/net_loop.c index bfb356b5..0cd6662e 100644 --- a/net_loop.c +++ b/net_loop.c @@ -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) diff --git a/net_loop.h b/net_loop.h index 4f248f49..2d62a6c0 100644 --- a/net_loop.h +++ b/net_loop.h @@ -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 diff --git a/net_main.c b/net_main.c index a7137ab3..ed2d341d 100644 --- a/net_main.c +++ b/net_main.c @@ -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 +#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 index 00000000..93257124 --- /dev/null +++ b/net_master.h @@ -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 diff --git a/net_udp.c b/net_udp.c index b7762980..2ec8e9ce 100644 --- 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); diff --git a/net_udp.h b/net_udp.h index 06b531bf..1210e721 100644 --- 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); diff --git a/net_win.c b/net_win.c index d34348cd..725eef4f 100644 --- 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, diff --git a/net_wins.c b/net_wins.c index 5a12f52c..16c1eb7a 100644 --- a/net_wins.c +++ b/net_wins.c @@ -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); diff --git a/net_wins.h b/net_wins.h index a90da5b3..7f401ab0 100644 --- a/net_wins.h +++ b/net_wins.h @@ -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); diff --git a/net_wipx.c b/net_wipx.c index f1d21236..3e62cb4c 100644 --- a/net_wipx.c +++ b/net_wipx.c @@ -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) diff --git a/net_wipx.h b/net_wipx.h index b8caf436..120b2ab3 100644 --- a/net_wipx.h +++ b/net_wipx.h @@ -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); diff --git a/sv_main.c b/sv_main.c index 17f5f500..9dd462f3 100644 --- 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 (); }