diff options
Diffstat (limited to 'code/server/sv_client.c')
-rw-r--r-- | code/server/sv_client.c | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/code/server/sv_client.c b/code/server/sv_client.c index c9915b9..6f932d1 100644 --- a/code/server/sv_client.c +++ b/code/server/sv_client.c @@ -1083,6 +1083,50 @@ void SV_WriteDownloadToClient( client_t *cl , msg_t *msg ) } } +#if 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; + + 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 @@ -1326,6 +1370,11 @@ void SV_UserinfoChanged( client_t *cl ) { cl->snapshotMsec = 50; } +#if USE_VOIP + val = Info_ValueForKey (cl->userinfo, "voip"); + cl->hasVoip = (strlen(val) && atoi(val)) ? qtrue : qfalse; +#endif + // TTimo // maintain the IP information // the banning code relies on this being consistently present @@ -1361,6 +1410,39 @@ static void SV_UpdateUserinfo_f( client_t *cl ) { VM_Call( gvm, GAME_CLIENT_USERINFO_CHANGED, cl - svs.clients ); } + +#if 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 ); @@ -1376,6 +1458,10 @@ static ucmd_t ucmds[] = { {"stopdl", SV_StopDownload_f}, {"donedl", SV_DoneDownload_f}, +#if USE_VOIP + {"voip", SV_Voip_f}, +#endif + {NULL, NULL} }; @@ -1596,6 +1682,118 @@ static void SV_UserMove( client_t *cl, msg_t *msg, qboolean delta ) { } +#if 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 + + + /* =========================================================================== @@ -1699,6 +1897,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 ); +#if USE_VOIP + } else if ( c == clc_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) ); } |