summaryrefslogtreecommitdiff
path: root/src/server/sv_client.c
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/sv_client.c
parent09ceb08b95978feb0a9b737f22ac0f662c7465d6 (diff)
* Merge ioq3-r1423
+ IPv6 + VoIP + Stereo rendering + Other minor stuff
Diffstat (limited to 'src/server/sv_client.c')
-rw-r--r--src/server/sv_client.c241
1 files changed, 236 insertions, 5 deletions
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) );
}