summaryrefslogtreecommitdiff
path: root/src/server
diff options
context:
space:
mode:
authorTim Angus <tim@ngus.net>2009-10-03 11:52:53 +0000
committerTim Angus <tim@ngus.net>2013-01-03 00:15:28 +0000
commitb47a49a03370e7ea42f47623b9f72a5ca799f0e7 (patch)
tree9d64d778ded2971d7ebd05970d903d886bd81436 /src/server
parent09ceb08b95978feb0a9b737f22ac0f662c7465d6 (diff)
* Merge ioq3-r1423
+ IPv6 + VoIP + Stereo rendering + Other minor stuff
Diffstat (limited to 'src/server')
-rw-r--r--src/server/server.h32
-rw-r--r--src/server/sv_ccmds.c118
-rw-r--r--src/server/sv_client.c241
-rw-r--r--src/server/sv_init.c9
-rw-r--r--src/server/sv_main.c18
-rw-r--r--src/server/sv_rankings.c2
-rw-r--r--src/server/sv_snapshot.c4
7 files changed, 293 insertions, 131 deletions
diff --git a/src/server/server.h b/src/server/server.h
index 331937e4..bdcd8729 100644
--- a/src/server/server.h
+++ b/src/server/server.h
@@ -34,6 +34,18 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define MAX_ENT_CLUSTERS 16
+#ifdef USE_VOIP
+typedef struct voipServerPacket_s
+{
+ int generation;
+ int sequence;
+ int frames;
+ int len;
+ int sender;
+ byte data[1024];
+} voipServerPacket_t;
+#endif
+
typedef struct svEntity_s {
struct worldSector_s *worldSector;
struct svEntity_s *nextEntityInWorldSector;
@@ -168,6 +180,14 @@ typedef struct client_s {
netchan_buffer_t *netchan_start_queue;
netchan_buffer_t **netchan_end_queue;
+#ifdef USE_VOIP
+ qboolean hasVoip;
+ qboolean muteAllVoip;
+ qboolean ignoreVoipFromClient[MAX_CLIENTS];
+ voipServerPacket_t voipPacket[64]; // !!! FIXME: WAY too much memory!
+ int queuedVoipPackets;
+#endif
+
int oldServerTime;
qboolean csUpdated[MAX_CONFIGSTRINGS+1];
} client_t;
@@ -250,6 +270,11 @@ extern cvar_t *sv_pure;
extern cvar_t *sv_lanForceRate;
extern cvar_t *sv_dequeuePeriod;
+#ifdef USE_VOIP
+extern cvar_t *sv_voip;
+#endif
+
+
//===========================================================
//
@@ -292,8 +317,6 @@ void SV_GetChallenge( netadr_t from );
void SV_DirectConnect( netadr_t from );
-void SV_AuthorizeIpPacket( netadr_t from );
-
void SV_ExecuteClientMessage( client_t *cl, msg_t *msg );
void SV_UserinfoChanged( client_t *cl );
@@ -305,6 +328,11 @@ void SV_ClientThink (client_t *cl, usercmd_t *cmd);
void SV_WriteDownloadToClient( client_t *cl , msg_t *msg );
+#ifdef USE_VOIP
+void SV_WriteVoipToClient( client_t *cl, msg_t *msg );
+#endif
+
+
//
// sv_ccmds.c
//
diff --git a/src/server/sv_ccmds.c b/src/server/sv_ccmds.c
index 33926d57..60de4275 100644
--- a/src/server/sv_ccmds.c
+++ b/src/server/sv_ccmds.c
@@ -386,122 +386,6 @@ static void SV_Kick_f( void ) {
/*
==================
-SV_Ban_f
-
-Ban a user from being able to play on this server through the auth
-server
-==================
-*/
-static void SV_Ban_f( void ) {
- client_t *cl;
-
- // make sure server is running
- if ( !com_sv_running->integer ) {
- Com_Printf( "Server is not running.\n" );
- return;
- }
-
- if ( Cmd_Argc() != 2 ) {
- Com_Printf ("Usage: banUser <player name>\n");
- return;
- }
-
- cl = SV_GetPlayerByHandle();
-
- if (!cl) {
- return;
- }
-
- if( cl->netchan.remoteAddress.type == NA_LOOPBACK ) {
- SV_SendServerCommand(NULL, "print \"%s\"", "Cannot kick host player\n");
- return;
- }
-
- //FIXME: there is no auth server in Tremulous
-#if 0
- // look up the authorize server's IP
- if ( !svs.authorizeAddress.ip[0] && svs.authorizeAddress.type != NA_BAD ) {
- Com_Printf( "Resolving %s\n", AUTHORIZE_SERVER_NAME );
- if ( !NET_StringToAdr( AUTHORIZE_SERVER_NAME, &svs.authorizeAddress ) ) {
- Com_Printf( "Couldn't resolve address\n" );
- return;
- }
- svs.authorizeAddress.port = BigShort( PORT_AUTHORIZE );
- Com_Printf( "%s resolved to %i.%i.%i.%i:%i\n", AUTHORIZE_SERVER_NAME,
- svs.authorizeAddress.ip[0], svs.authorizeAddress.ip[1],
- svs.authorizeAddress.ip[2], svs.authorizeAddress.ip[3],
- BigShort( svs.authorizeAddress.port ) );
- }
-
- // otherwise send their ip to the authorize server
- if ( svs.authorizeAddress.type != NA_BAD ) {
- NET_OutOfBandPrint( NS_SERVER, svs.authorizeAddress,
- "banUser %i.%i.%i.%i", cl->netchan.remoteAddress.ip[0], cl->netchan.remoteAddress.ip[1],
- cl->netchan.remoteAddress.ip[2], cl->netchan.remoteAddress.ip[3] );
- Com_Printf("%s was banned from coming back\n", cl->name);
- }
-#endif
-}
-
-/*
-==================
-SV_BanNum_f
-
-Ban a user from being able to play on this server through the auth
-server
-==================
-*/
-static void SV_BanNum_f( void ) {
- client_t *cl;
-
- // make sure server is running
- if ( !com_sv_running->integer ) {
- Com_Printf( "Server is not running.\n" );
- return;
- }
-
- if ( Cmd_Argc() != 2 ) {
- Com_Printf ("Usage: banClient <client number>\n");
- return;
- }
-
- cl = SV_GetPlayerByNum();
- if ( !cl ) {
- return;
- }
- if( cl->netchan.remoteAddress.type == NA_LOOPBACK ) {
- SV_SendServerCommand(NULL, "print \"%s\"", "Cannot kick host player\n");
- return;
- }
-
- //FIXME: there is no auth server in Tremulous
-#if 0
- // look up the authorize server's IP
- if ( !svs.authorizeAddress.ip[0] && svs.authorizeAddress.type != NA_BAD ) {
- Com_Printf( "Resolving %s\n", AUTHORIZE_SERVER_NAME );
- if ( !NET_StringToAdr( AUTHORIZE_SERVER_NAME, &svs.authorizeAddress ) ) {
- Com_Printf( "Couldn't resolve address\n" );
- return;
- }
- svs.authorizeAddress.port = BigShort( PORT_AUTHORIZE );
- Com_Printf( "%s resolved to %i.%i.%i.%i:%i\n", AUTHORIZE_SERVER_NAME,
- svs.authorizeAddress.ip[0], svs.authorizeAddress.ip[1],
- svs.authorizeAddress.ip[2], svs.authorizeAddress.ip[3],
- BigShort( svs.authorizeAddress.port ) );
- }
-
- // otherwise send their ip to the authorize server
- if ( svs.authorizeAddress.type != NA_BAD ) {
- NET_OutOfBandPrint( NS_SERVER, svs.authorizeAddress,
- "banUser %i.%i.%i.%i", cl->netchan.remoteAddress.ip[0], cl->netchan.remoteAddress.ip[1],
- cl->netchan.remoteAddress.ip[2], cl->netchan.remoteAddress.ip[3] );
- Com_Printf("%s was banned from coming back\n", cl->name);
- }
-#endif
-}
-
-/*
-==================
SV_KickNum_f
Kick a user off of the server FIXME: move to game
@@ -729,8 +613,6 @@ void SV_AddOperatorCommands( void ) {
Cmd_AddCommand ("heartbeat", SV_Heartbeat_f);
Cmd_AddCommand ("kick", SV_Kick_f);
Cmd_AddCommand ("kickAll", SV_KickAll_f);
- Cmd_AddCommand ("banUser", SV_Ban_f);
- Cmd_AddCommand ("banClient", SV_BanNum_f);
Cmd_AddCommand ("clientkick", SV_KickNum_f);
Cmd_AddCommand ("status", SV_Status_f);
Cmd_AddCommand ("serverinfo", SV_Serverinfo_f);
diff --git a/src/server/sv_client.c b/src/server/sv_client.c
index 6aa7797b..ca8dd86d 100644
--- a/src/server/sv_client.c
+++ b/src/server/sv_client.c
@@ -106,7 +106,7 @@ void SV_DirectConnect( netadr_t from ) {
char *ip;
Com_DPrintf ("SVC_DirectConnect ()\n");
-
+
Q_strncpyz( userinfo, Cmd_Argv(1), sizeof(userinfo) );
version = atoi( Info_ValueForKey( userinfo, "protocol" ) );
@@ -155,9 +155,8 @@ void SV_DirectConnect( netadr_t from ) {
for (i=0 ; i<MAX_CHALLENGES ; i++) {
if (NET_CompareAdr(from, svs.challenges[i].adr)) {
- if ( challenge == svs.challenges[i].challenge ) {
- break; // good
- }
+ if ( challenge == svs.challenges[i].challenge )
+ break;
}
}
if (i == MAX_CHALLENGES) {
@@ -656,11 +655,13 @@ void SV_WriteDownloadToClient( client_t *cl , msg_t *msg )
}
}
+ cl->download = 0;
+
// We open the file here
if ( !(sv_allowDownload->integer & DLF_ENABLE) ||
(sv_allowDownload->integer & DLF_NO_UDP) ||
idPack || unreferenced ||
- ( cl->downloadSize = FS_SV_FOpenFileRead( cl->downloadName, &cl->download ) ) <= 0 ) {
+ ( cl->downloadSize = FS_SV_FOpenFileRead( cl->downloadName, &cl->download ) ) < 0 ) {
// cannot auto-download file
if(unreferenced)
{
@@ -703,6 +704,10 @@ void SV_WriteDownloadToClient( client_t *cl , msg_t *msg )
MSG_WriteString( msg, errorMessage );
*cl->downloadName = 0;
+
+ if(cl->download)
+ FS_FCloseFile(cl->download);
+
return;
}
@@ -825,6 +830,58 @@ void SV_WriteDownloadToClient( client_t *cl , msg_t *msg )
}
}
+#ifdef USE_VOIP
+/*
+==================
+SV_WriteVoipToClient
+
+Check to see if there is any VoIP queued for a client, and send if there is.
+==================
+*/
+void SV_WriteVoipToClient( client_t *cl, msg_t *msg )
+{
+ voipServerPacket_t *packet = &cl->voipPacket[0];
+ int totalbytes = 0;
+ int i;
+
+ if (*cl->downloadName) {
+ cl->queuedVoipPackets = 0;
+ return; // no VoIP allowed if download is going, to save bandwidth.
+ }
+
+ // Write as many VoIP packets as we reasonably can...
+ for (i = 0; i < cl->queuedVoipPackets; i++, packet++) {
+ totalbytes += packet->len;
+ if (totalbytes > MAX_DOWNLOAD_BLKSIZE)
+ break;
+
+ // You have to start with a svc_EOF, so legacy clients drop the
+ // rest of this packet. Otherwise, those without VoIP support will
+ // see the svc_voip command, then panic and disconnect.
+ // Generally we don't send VoIP packets to legacy clients, but this
+ // serves as both a safety measure and a means to keep demo files
+ // compatible.
+ MSG_WriteByte( msg, svc_EOF );
+ MSG_WriteByte( msg, svc_extension );
+ MSG_WriteByte( msg, svc_voip );
+ MSG_WriteShort( msg, packet->sender );
+ MSG_WriteByte( msg, (byte) packet->generation );
+ MSG_WriteLong( msg, packet->sequence );
+ MSG_WriteByte( msg, packet->frames );
+ MSG_WriteShort( msg, packet->len );
+ MSG_WriteData( msg, packet->data, packet->len );
+ }
+
+ // !!! FIXME: I hate this queue system.
+ cl->queuedVoipPackets -= i;
+ if (cl->queuedVoipPackets > 0) {
+ memmove( &cl->voipPacket[0], &cl->voipPacket[i],
+ sizeof (voipServerPacket_t) * i);
+ }
+}
+#endif
+
+
/*
=================
SV_Disconnect_f
@@ -1072,6 +1129,13 @@ void SV_UserinfoChanged( client_t *cl ) {
cl->snapshotMsec = 50;
}
+#ifdef USE_VOIP
+ // in the future, (val) will be a protocol version string, so only
+ // accept explicitly 1, not generally non-zero.
+ val = Info_ValueForKey (cl->userinfo, "cl_voip");
+ cl->hasVoip = (atoi(val) == 1) ? qtrue : qfalse;
+#endif
+
// TTimo
// maintain the IP information
// the banning code relies on this being consistently present
@@ -1107,6 +1171,39 @@ static void SV_UpdateUserinfo_f( client_t *cl ) {
VM_Call( gvm, GAME_CLIENT_USERINFO_CHANGED, cl - svs.clients );
}
+
+#ifdef USE_VOIP
+static
+void SV_UpdateVoipIgnore(client_t *cl, const char *idstr, qboolean ignore)
+{
+ if ((*idstr >= '0') && (*idstr <= '9')) {
+ const int id = atoi(idstr);
+ if ((id >= 0) && (id < MAX_CLIENTS)) {
+ cl->ignoreVoipFromClient[id] = ignore;
+ }
+ }
+}
+
+/*
+==================
+SV_UpdateUserinfo_f
+==================
+*/
+static void SV_Voip_f( client_t *cl ) {
+ const char *cmd = Cmd_Argv(1);
+ if (strcmp(cmd, "ignore") == 0) {
+ SV_UpdateVoipIgnore(cl, Cmd_Argv(2), qtrue);
+ } else if (strcmp(cmd, "unignore") == 0) {
+ SV_UpdateVoipIgnore(cl, Cmd_Argv(2), qfalse);
+ } else if (strcmp(cmd, "muteall") == 0) {
+ cl->muteAllVoip = qtrue;
+ } else if (strcmp(cmd, "unmuteall") == 0) {
+ cl->muteAllVoip = qfalse;
+ }
+}
+#endif
+
+
typedef struct {
char *name;
void (*func)( client_t *cl );
@@ -1122,6 +1219,10 @@ static ucmd_t ucmds[] = {
{"stopdl", SV_StopDownload_f},
{"donedl", SV_DoneDownload_f},
+#ifdef USE_VOIP
+ {"voip", SV_Voip_f},
+#endif
+
{NULL, NULL}
};
@@ -1344,6 +1445,118 @@ static void SV_UserMove( client_t *cl, msg_t *msg, qboolean delta ) {
}
+#ifdef USE_VOIP
+static
+qboolean SV_ShouldIgnoreVoipSender(const client_t *cl)
+{
+ if (!sv_voip->integer)
+ return qtrue; // VoIP disabled on this server.
+ else if (!cl->hasVoip) // client doesn't have VoIP support?!
+ return qtrue;
+
+ // !!! FIXME: implement player blacklist.
+
+ return qfalse; // don't ignore.
+}
+
+static
+void SV_UserVoip( client_t *cl, msg_t *msg ) {
+ const int sender = (int) (cl - svs.clients);
+ const int generation = MSG_ReadByte(msg);
+ const int sequence = MSG_ReadLong(msg);
+ const int frames = MSG_ReadByte(msg);
+ const int recip1 = MSG_ReadLong(msg);
+ const int recip2 = MSG_ReadLong(msg);
+ const int recip3 = MSG_ReadLong(msg);
+ const int packetsize = MSG_ReadShort(msg);
+ byte encoded[sizeof (cl->voipPacket[0].data)];
+ client_t *client = NULL;
+ voipServerPacket_t *packet = NULL;
+ int i;
+
+ if (generation < 0)
+ return; // short/invalid packet, bail.
+ else if (sequence < 0)
+ return; // short/invalid packet, bail.
+ else if (frames < 0)
+ return; // short/invalid packet, bail.
+ else if (recip1 < 0)
+ return; // short/invalid packet, bail.
+ else if (recip2 < 0)
+ return; // short/invalid packet, bail.
+ else if (recip3 < 0)
+ return; // short/invalid packet, bail.
+ else if (packetsize < 0)
+ return; // short/invalid packet, bail.
+
+ if (packetsize > sizeof (encoded)) { // overlarge packet?
+ int bytesleft = packetsize;
+ while (bytesleft) {
+ int br = bytesleft;
+ if (br > sizeof (encoded))
+ br = sizeof (encoded);
+ MSG_ReadData(msg, encoded, br);
+ bytesleft -= br;
+ }
+ return; // overlarge packet, bail.
+ }
+
+ MSG_ReadData(msg, encoded, packetsize);
+
+ if (SV_ShouldIgnoreVoipSender(cl))
+ return; // Blacklisted, disabled, etc.
+
+ // !!! FIXME: see if we read past end of msg...
+
+ // !!! FIXME: reject if not speex narrowband codec.
+ // !!! FIXME: decide if this is bogus data?
+
+ // (the three recip* values are 31 bits each (ignores sign bit so we can
+ // get a -1 error from MSG_ReadLong() ... ), allowing for 93 clients.)
+ assert( sv_maxclients->integer < 93 );
+
+ // decide who needs this VoIP packet sent to them...
+ for (i = 0, client = svs.clients; i < sv_maxclients->integer ; i++, client++) {
+ if (client->state != CS_ACTIVE)
+ continue; // not in the game yet, don't send to this guy.
+ else if (i == sender)
+ continue; // don't send voice packet back to original author.
+ else if (!client->hasVoip)
+ continue; // no VoIP support, or support disabled.
+ else if (client->muteAllVoip)
+ continue; // client is ignoring everyone.
+ else if (client->ignoreVoipFromClient[sender])
+ continue; // client is ignoring this talker.
+ else if (*cl->downloadName) // !!! FIXME: possible to DoS?
+ continue; // no VoIP allowed if downloading, to save bandwidth.
+ else if ( ((i >= 0) && (i < 31)) && ((recip1 & (1 << (i-0))) == 0) )
+ continue; // not addressed to this player.
+ else if ( ((i >= 31) && (i < 62)) && ((recip2 & (1 << (i-31))) == 0) )
+ continue; // not addressed to this player.
+ else if ( ((i >= 62) && (i < 93)) && ((recip3 & (1 << (i-62))) == 0) )
+ continue; // not addressed to this player.
+
+ // Transmit this packet to the client.
+ // !!! FIXME: I don't like this queueing system.
+ if (client->queuedVoipPackets >= (sizeof (client->voipPacket) / sizeof (client->voipPacket[0]))) {
+ Com_Printf("Too many VoIP packets queued for client #%d\n", i);
+ continue; // no room for another packet right now.
+ }
+
+ packet = &client->voipPacket[client->queuedVoipPackets];
+ packet->sender = sender;
+ packet->frames = frames;
+ packet->len = packetsize;
+ packet->generation = generation;
+ packet->sequence = sequence;
+ memcpy(packet->data, encoded, packetsize);
+ client->queuedVoipPackets++;
+ }
+}
+#endif
+
+
+
/*
===========================================================================
@@ -1428,9 +1641,23 @@ void SV_ExecuteClientMessage( client_t *cl, msg_t *msg ) {
// read optional clientCommand strings
do {
c = MSG_ReadByte( msg );
+
+ // See if this is an extension command after the EOF, which means we
+ // got data that a legacy server should ignore.
+ if ((c == clc_EOF) && (MSG_LookaheadByte( msg ) == clc_extension)) {
+ MSG_ReadByte( msg ); // throw the clc_extension byte away.
+ c = MSG_ReadByte( msg ); // something legacy servers can't do!
+ // sometimes you get a clc_extension at end of stream...dangling
+ // bits in the huffman decoder giving a bogus value?
+ if (c == -1) {
+ c = clc_EOF;
+ }
+ }
+
if ( c == clc_EOF ) {
break;
}
+
if ( c != clc_clientCommand ) {
break;
}
@@ -1447,6 +1674,10 @@ void SV_ExecuteClientMessage( client_t *cl, msg_t *msg ) {
SV_UserMove( cl, msg, qtrue );
} else if ( c == clc_moveNoDelta ) {
SV_UserMove( cl, msg, qfalse );
+ } else if ( c == clc_voip ) {
+#ifdef USE_VOIP
+ SV_UserVoip( cl, msg );
+#endif
} else if ( c != clc_EOF ) {
Com_Printf( "WARNING: bad command byte for client %i\n", (int) (cl - svs.clients) );
}
diff --git a/src/server/sv_init.c b/src/server/sv_init.c
index 5d760519..d9930f29 100644
--- a/src/server/sv_init.c
+++ b/src/server/sv_init.c
@@ -287,6 +287,9 @@ void SV_Startup( void ) {
}
Cvar_Set( "sv_running", "1" );
+
+ // Join the ipv6 multicast group now that a map is running so clients can scan for us on the local network.
+ NET_JoinMulticast6();
}
@@ -607,6 +610,10 @@ void SV_Init (void) {
Cvar_Get ("sv_cheats", "1", CVAR_SYSTEMINFO | CVAR_ROM );
sv_serverid = Cvar_Get ("sv_serverid", "0", CVAR_SYSTEMINFO | CVAR_ROM );
sv_pure = Cvar_Get ("sv_pure", "1", CVAR_SYSTEMINFO );
+#ifdef USE_VOIP
+ sv_voip = Cvar_Get ("sv_voip", "1", CVAR_SYSTEMINFO | CVAR_LATCH);
+ Cvar_CheckRange( sv_voip, 0, 1, qtrue );
+#endif
Cvar_Get ("sv_paks", "", CVAR_SYSTEMINFO | CVAR_ROM );
Cvar_Get ("sv_pakNames", "", CVAR_SYSTEMINFO | CVAR_ROM );
Cvar_Get ("sv_referencedPaks", "", CVAR_SYSTEMINFO | CVAR_ROM );
@@ -687,6 +694,8 @@ void SV_Shutdown( char *finalmsg ) {
Com_Printf( "----- Server Shutdown (%s) -----\n", finalmsg );
+ NET_LeaveMulticast6();
+
if ( svs.clients && !com_errorEntered ) {
SV_FinalMessage( finalmsg );
}
diff --git a/src/server/sv_main.c b/src/server/sv_main.c
index 2940d95c..7b66aa6f 100644
--- a/src/server/sv_main.c
+++ b/src/server/sv_main.c
@@ -23,6 +23,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "server.h"
+#ifdef USE_VOIP
+cvar_t *sv_voip;
+#endif
+
serverStatic_t svs; // persistant server info
server_t sv; // local server
vm_t *gvm = NULL; // game virtual machine
@@ -247,16 +251,14 @@ void SV_MasterHeartbeat( void ) {
sv_master[i]->modified = qfalse;
Com_Printf( "Resolving %s\n", sv_master[i]->string );
- if ( !NET_StringToAdr( sv_master[i]->string, &adr[i] ) ) {
+ if ( !NET_StringToAdr( sv_master[i]->string, &adr[i], NA_UNSPEC ) ) {
Com_Printf( "Couldn't resolve address: %s\n", sv_master[i]->string );
continue;
}
if ( !strchr( sv_master[i]->string, ':' ) ) {
adr[i].port = BigShort( 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],
- BigShort( adr[i].port ) );
+ Com_Printf( "%s resolved to %s\n", sv_master[i]->string, NET_AdrToStringwPort(adr[i]));
}
@@ -300,7 +302,7 @@ void SV_MasterGameStat( const char *data )
return; // only dedicated servers send stats
Com_Printf( "Resolving %s\n", MASTER_SERVER_NAME );
- if( !NET_StringToAdr( MASTER_SERVER_NAME, &adr ) )
+ if( !NET_StringToAdr( MASTER_SERVER_NAME, &adr, NA_IP ) )
{
Com_Printf( "Couldn't resolve address: %s\n", MASTER_SERVER_NAME );
return;
@@ -417,6 +419,12 @@ void SVC_Info( netadr_t from ) {
va("%i", sv_maxclients->integer - sv_privateClients->integer ) );
Info_SetValueForKey( infostring, "pure", va("%i", sv_pure->integer ) );
+#ifdef USE_VOIP
+ if (sv_voip->integer) {
+ Info_SetValueForKey( infostring, "voip", va("%i", sv_voip->integer ) );
+ }
+#endif
+
if( sv_minPing->integer ) {
Info_SetValueForKey( infostring, "minPing", va("%i", sv_minPing->integer) );
}
diff --git a/src/server/sv_rankings.c b/src/server/sv_rankings.c
index 20d24fd4..7846cccf 100644
--- a/src/server/sv_rankings.c
+++ b/src/server/sv_rankings.c
@@ -1524,7 +1524,7 @@ static void SV_RankError( const char* fmt, ... )
char text[1024];
va_start( arg_ptr, fmt );
- vsprintf( text, fmt, arg_ptr );
+ Q_vsnprintf(text, sizeof(text), fmt, arg_ptr );
va_end( arg_ptr );
Com_DPrintf( "****************************************\n" );
diff --git a/src/server/sv_snapshot.c b/src/server/sv_snapshot.c
index 47471ba5..037b772d 100644
--- a/src/server/sv_snapshot.c
+++ b/src/server/sv_snapshot.c
@@ -648,6 +648,10 @@ void SV_SendClientSnapshot( client_t *client ) {
// Add any download data if the client is downloading
SV_WriteDownloadToClient( client, &msg );
+#ifdef USE_VOIP
+ SV_WriteVoipToClient( client, &msg );
+#endif
+
// check for overflow
if ( msg.overflowed ) {
Com_Printf ("WARNING: msg overflowed for %s\n", client->name);