/* ================= SV_SendServerCommand Sends a reliable command string to be interpreted by the client game module: "cp", "print", "chat", etc A NULL client will broadcast to all clients ================= */ void QDECL SV_SendServerCommand(client_t *cl, const char *fmt, ...) { va_list argptr; byte message[MAX_MSGLEN]; client_t *client; int j; va_start (argptr,fmt); Q_vsnprintf ((char *)message, sizeof(message), fmt,argptr); va_end (argptr); // Fix to http://aluigi.altervista.org/adv/q3msgboom-adv.txt // The actual cause of the bug is probably further downstream // and should maybe be addressed later, but this certainly // fixes the problem for now if ( strlen ((char *)message) > 1022 ) { return; } if ( cl != NULL ) { SV_AddServerCommand( cl, (char *)message ); return; } // hack to echo broadcast prints to console if ( com_dedicated->integer && !strncmp( (char *)message, "print", 5) ) { Com_Printf ("broadcast: %s\n", SV_ExpandNewlines((char *)message) ); } // send the data to all relevent clients for (j = 0, client = svs.clients; j < sv_maxclients->integer ; j++, client++) { SV_AddServerCommand( client, (char *)message ); } }
/* ================= SV_SendServerCommand Sends a reliable command string to be interpreted by the client game module: "cp", "print", "chat", etc A NULL client will broadcast to all clients ================= */ void QDECL SV_SendServerCommand( client_t *cl, const char *fmt, ... ) { va_list argptr; byte message[MAX_MSGLEN]; client_t *client; int j; va_start( argptr,fmt ); vsprintf( (char *)message, fmt,argptr ); va_end( argptr ); if ( cl != NULL ) { SV_AddServerCommand( cl, (char *)message ); return; } // hack to echo broadcast prints to console if ( com_dedicated->integer && !strncmp( (char *)message, "print", 5 ) ) { Com_Printf( "broadcast: %s\n", SV_ExpandNewlines( (char *)message ) ); } // send the data to all relevent clients for ( j = 0, client = svs.clients; j < sv_maxclients->integer ; j++, client++ ) { if ( client->state < CS_PRIMED ) { continue; } // Ridah, don't need to send messages to AI if ( client->gentity && client->gentity->r.svFlags & SVF_CASTAI ) { continue; } // done. SV_AddServerCommand( client, (char *)message ); } }
/* ================== SV_ConTell_f ================== */ static void SV_ConTell_f(void) { char text[MAX_SAY_TEXT] = {0}; client_t *cl; if( !com_dedicated->integer ) { Com_Printf( "Server is not dedicated.\n" ); return; } // make sure server is running if ( !com_sv_running->integer ) { Com_Printf( "Server is not running.\n" ); return; } if ( Cmd_Argc () < 3 ) { Com_Printf ("Usage: svtell <client number> <text>\n"); return; } cl = SV_GetPlayerByNum(); if ( !cl ) { return; } Cmd_ArgsFromBuffer( 2, text, sizeof(text) ); Com_Printf ("tell: svtell to %s" S_COLOR_WHITE ": %s\n", cl->name, SV_ExpandNewlines((char *)text) ); SV_SendServerCommand(cl, "chat \"" SVTELL_PREFIX S_COLOR_MAGENTA "%s" S_COLOR_WHITE "\"\n", text); }
/* ================= SV_SendServerCommand Sends a reliable command string to be interpreted by the client game module: "cp", "print", "chat", etc A NULL client will broadcast to all clients ================= */ void QDECL SV_SendServerCommand(client_t *cl, const char *fmt, ...) { va_list argptr; byte message[MAX_MSGLEN]; client_t *client; int j; int msglen; va_start (argptr,fmt); Q_vsnprintf ((char *)message, sizeof(message), fmt,argptr); va_end (argptr); msglen = strlen((char *)message); // Fix to http://aluigi.altervista.org/adv/q3msgboom-adv.txt // The actual cause of the bug is probably further downstream // and should maybe be addressed later, but this certainly // fixes the problem for now if ( msglen > 1022 ) { return; } if (sv.incognitoJoinSpec && cl == NULL && (!Q_strncmp((char *) message, "print \"", 7)) && msglen >= 27 + 7 && !strcmp("^7 joined the spectators.\n\"", ((char *) message) + msglen - 27)) { return; } ///////////////////////////////////////////////////////// // separator for incognito.patch and specchatglobal.patch ///////////////////////////////////////////////////////// if (sv_specChatGlobal->integer > 0 && cl != NULL && !Q_strncmp((char *) message, "chat \"^7(SPEC) ", 15)) { if (!Q_strncmp((char *) message, sv.lastSpecChat, sizeof(sv.lastSpecChat) - 1)) { return; } Q_strncpyz(sv.lastSpecChat, (char *) message, sizeof(sv.lastSpecChat)); cl = NULL; } if ( cl != NULL ) { SV_AddServerCommand( cl, (char *)message ); return; } // hack to echo broadcast prints to console if ( com_dedicated->integer && !strncmp( (char *)message, "print", 5) ) { Com_Printf ("broadcast: %s\n", SV_ExpandNewlines((char *)message) ); } // send the data to all relevent clients for (j = 0, client = svs.clients; j < sv_maxclients->integer ; j++, client++) { SV_AddServerCommand( client, (char *)message ); } }
/** * @brief Sends a reliable command string to be interpreted by the client game * module: "cp", "print", "chat", etc * * A NULL client will broadcast to all clients */ void QDECL SV_SendServerCommand(client_t *cl, const char *fmt, ...) { va_list argptr; byte message[MAX_MSGLEN]; client_t *client; int j; va_start(argptr, fmt); Q_vsnprintf((char *)message, sizeof(message), fmt, argptr); va_end(argptr); // do not forward server command messages that would be too big to clients // ( q3infoboom / q3msgboom stuff ) // see http://aluigi.altervista.org/adv/q3msgboom-adv.txt if (strlen((char *)message) > 1022) { SV_WriteAttackLog("Warning: q3infoboom/q3msgboom exploit attack.\n"); // FIXME: add client slot return; } if (cl != NULL) { SV_AddServerCommand(cl, (char *)message); return; } // hack to echo broadcast prints to console if (com_dedicated->integer && !strncmp((char *)message, "print", 5)) { Com_Printf("broadcast: %s\n", SV_ExpandNewlines((char *)message)); } // send the data to all relevent clients for (j = 0, client = svs.clients; j < sv_maxclients->integer ; j++, client++) { if (client->state < CS_PRIMED) { continue; } // don't need to send messages to AI if (client->gentity && (client->gentity->r.svFlags & SVF_BOT)) { continue; } SV_AddServerCommand(client, (char *)message); } }
/* ================= SV_SendServerCommand Sends a reliable command string to be interpreted by the client game module: "cp", "print", "chat", etc A NULL client will broadcast to all clients ================= */ void QDECL SV_SendServerCommand(client_t *cl, const char *fmt, ...) { va_list argptr; byte message[MAX_MSGLEN]; client_t *client; int j; va_start (argptr,fmt); Q_vsnprintf ((char *)message, sizeof(message), fmt,argptr); va_end (argptr); // Fix to http://aluigi.altervista.org/adv/q3msgboom-adv.txt // The actual cause of the bug is probably further downstream // and should maybe be addressed later, but this certainly // fixes the problem for now if ( strlen ((char *)message) > 1022 ) { return; } if ( cl != NULL ) { SV_AddServerCommand( cl, (char *)message ); return; } // hack to echo broadcast prints to console if ( com_dedicated->integer && !strncmp( (char *)message, "print", 5) ) { Com_Printf ("broadcast: %s\n", SV_ExpandNewlines((char *)message) ); } // save broadcasts to demo // note: in the case a command is only issued to a specific client, it is NOT recorded (see above when cl != NULL). If you want to record them, just place this code above, but be warned that it may be dangerous (such as "disconnect" command) because server commands will be replayed to every connected clients! if ( sv.demoState == DS_RECORDING ) { SV_DemoWriteServerCommand( (char *)message ); } // send the data to all relevent clients for (j = 0, client = svs.clients; j < sv_maxclients->integer ; j++, client++) { SV_AddServerCommand( client, (char *)message ); } }
/* ================== SV_ConSay_f ================== */ static void SV_ConSay_f(void) { char text[MAX_SAY_TEXT] = {0}; if( !com_dedicated->integer ) { Com_Printf( "Server is not dedicated.\n" ); return; } // make sure server is running if ( !com_sv_running->integer ) { Com_Printf( "Server is not running.\n" ); return; } if ( Cmd_Argc () < 2 ) { return; } Cmd_ArgsBuffer( text, sizeof(text) ); Com_Printf ("broadcast: chat \""SVSAY_PREFIX"%s\\n\"\n", SV_ExpandNewlines((char *)text) ); SV_SendServerCommand(NULL, "chat \""SVSAY_PREFIX"%s\"\n", text); }
/* ================= SV_SendServerCommand Sends a reliable command string to be interpreted by the client game module: "cp", "print", "chat", etc A NULL client will broadcast to all clients ================= */ void QDECL SV_SendServerCommand( client_t *cl, const char *fmt, ... ) { va_list argptr; byte message[MAX_MSGLEN]; client_t *client; int j; va_start( argptr,fmt ); #if defined RTCW_SP vsprintf( (char *)message, fmt,argptr ); #else Q_vsnprintf( (char *)message, sizeof( message ), fmt, argptr ); #endif // RTCW_XX va_end( argptr ); #if !defined RTCW_SP // do not forward server command messages that would be too big to clients // ( q3infoboom / q3msgboom stuff ) if ( strlen( (char *)message ) > 1022 ) { return; } #endif // RTCW_XX if ( cl != NULL ) { SV_AddServerCommand( cl, (char *)message ); return; } // hack to echo broadcast prints to console if ( com_dedicated->integer && !strncmp( (char *)message, "print", 5 ) ) { Com_Printf( "broadcast: %s\n", SV_ExpandNewlines( (char *)message ) ); } // send the data to all relevent clients for ( j = 0, client = svs.clients; j < sv_maxclients->integer ; j++, client++ ) { if ( client->state < CS_PRIMED ) { continue; } // Ridah, don't need to send messages to AI #if !defined RTCW_ET if ( client->gentity && client->gentity->r.svFlags & SVF_CASTAI ) { #else if ( client->gentity && client->gentity->r.svFlags & SVF_BOT ) { #endif // RTCW_XX continue; } // done. SV_AddServerCommand( client, (char *)message ); } } /* ============================================================================== MASTER SERVER FUNCTIONS ============================================================================== */ /* ================ SV_MasterHeartbeat Send a message to the masters every few minutes to let it know we are alive, and log information. We will also have a heartbeat sent when a server changes from empty to non-empty, and full to non-full, but not on every player enter or exit. ================ */ #define HEARTBEAT_MSEC 300 * 1000 #if !defined RTCW_ET #define HEARTBEAT_GAME "Wolfenstein-1" #else //#define HEARTBEAT_GAME "Wolfenstein-1" //#define HEARTBEAT_DEAD "WolfFlatline-1" // NERVE - SMF #define HEARTBEAT_GAME "EnemyTerritory-1" #endif // RTCW_XX #if defined RTCW_SP void SV_MasterHeartbeat( void ) { #else #if !defined RTCW_ET #define HEARTBEAT_DEAD "WolfFlatline-1" // NERVE - SMF #else #define HEARTBEAT_DEAD "ETFlatline-1" // NERVE - SMF #endif // RTCW_XX void SV_MasterHeartbeat( const char *hbname ) { #endif // RTCW_XX static netadr_t adr[MAX_MASTER_SERVERS]; int i; #if defined RTCW_MP // DHM - Nerve :: Update Server doesn't send heartbeat #ifdef UPDATE_SERVER return; #endif #endif // RTCW_XX #if defined RTCW_ET if ( SV_GameIsSinglePlayer() ) { return; // no heartbeats for SP } #endif // RTCW_XX // "dedicated 1" is for lan play, "dedicated 2" is for inet public play if ( !com_dedicated || com_dedicated->integer != 2 ) { return; // only dedicated servers send heartbeats } // if not time yet, don't send anything if ( svs.time < svs.nextHeartbeatTime ) { return; } svs.nextHeartbeatTime = svs.time + HEARTBEAT_MSEC; // send to group masters for ( i = 0 ; i < MAX_MASTER_SERVERS ; i++ ) { if ( !sv_master[i]->string[0] ) { continue; } // see if we haven't already resolved the name // resolving usually causes hitches on win95, so only // do it when needed if ( sv_master[i]->modified ) { sv_master[i]->modified = qfalse; Com_Printf( "Resolving %s\n", sv_master[i]->string ); if ( !NET_StringToAdr( sv_master[i]->string, &adr[i] ) ) { // if the address failed to resolve, clear it // so we don't take repeated dns hits Com_Printf( "Couldn't resolve address: %s\n", sv_master[i]->string ); Cvar_Set( sv_master[i]->name, "" ); sv_master[i]->modified = qfalse; continue; } if ( !strstr( ":", sv_master[i]->string ) ) { adr[i].port = rtcw::Endian::be( PORT_MASTER ); } Com_Printf( "%s resolved to %i.%i.%i.%i:%i\n", sv_master[i]->string, adr[i].ip[0], adr[i].ip[1], adr[i].ip[2], adr[i].ip[3], rtcw::Endian::be( adr[i].port ) ); } Com_Printf( "Sending heartbeat to %s\n", sv_master[i]->string ); // this command should be changed if the server info / status format // ever incompatably changes #if defined RTCW_SP NET_OutOfBandPrint( NS_SERVER, adr[i], "heartbeat %s\n", HEARTBEAT_GAME ); #else NET_OutOfBandPrint( NS_SERVER, adr[i], "heartbeat %s\n", hbname ); #endif // RTCW_XX } } #if !defined RTCW_SP /* ================= SV_MasterGameCompleteStatus NERVE - SMF - Sends gameCompleteStatus messages to all master servers ================= */ void SV_MasterGameCompleteStatus() { static netadr_t adr[MAX_MASTER_SERVERS]; int i; #if defined RTCW_ET if ( SV_GameIsSinglePlayer() ) { return; // no master game status for SP } #endif // RTCW_XX // "dedicated 1" is for lan play, "dedicated 2" is for inet public play if ( !com_dedicated || com_dedicated->integer != 2 ) { return; // only dedicated servers send master game status } // send to group masters for ( i = 0 ; i < MAX_MASTER_SERVERS ; i++ ) { if ( !sv_master[i]->string[0] ) { continue; } // see if we haven't already resolved the name // resolving usually causes hitches on win95, so only // do it when needed if ( sv_master[i]->modified ) { sv_master[i]->modified = qfalse; Com_Printf( "Resolving %s\n", sv_master[i]->string ); if ( !NET_StringToAdr( sv_master[i]->string, &adr[i] ) ) { // if the address failed to resolve, clear it // so we don't take repeated dns hits Com_Printf( "Couldn't resolve address: %s\n", sv_master[i]->string ); Cvar_Set( sv_master[i]->name, "" ); sv_master[i]->modified = qfalse; continue; } if ( !strstr( ":", sv_master[i]->string ) ) { adr[i].port = rtcw::Endian::be ( PORT_MASTER ); } Com_Printf( "%s resolved to %i.%i.%i.%i:%i\n", sv_master[i]->string, adr[i].ip[0], adr[i].ip[1], adr[i].ip[2], adr[i].ip[3], rtcw::Endian::be ( adr[i].port ) ); } Com_Printf( "Sending gameCompleteStatus to %s\n", sv_master[i]->string ); // this command should be changed if the server info / status format // ever incompatably changes SVC_GameCompleteStatus( adr[i] ); } } #endif // RTCW_XX /* ================= SV_MasterShutdown Informs all masters that this server is going down ================= */ void SV_MasterShutdown( void ) { // send a hearbeat right now svs.nextHeartbeatTime = -9999; #if defined RTCW_SP SV_MasterHeartbeat(); #else SV_MasterHeartbeat( HEARTBEAT_DEAD ); // NERVE - SMF - changed to flatline #endif // RTCW_XX // send it again to minimize chance of drops #if defined RTCW_SP svs.nextHeartbeatTime = -9999; SV_MasterHeartbeat(); #else // svs.nextHeartbeatTime = -9999; // SV_MasterHeartbeat( HEARTBEAT_DEAD ); #endif // RTCW_XX // when the master tries to poll the server, it won't respond, so // it will be removed from the list }