X-Git-Url: http://git.code-monkey.de/?a=blobdiff_plain;f=src%2Fclient.c;h=a992129cb774bcd3ba4eb6803a4cc38cc8799770;hb=0c57b93dfb882580f7ec43f0ddfea83c1c7ea729;hp=e4936e2419ef15f6091ceaa6bddd73ab25e5e9d6;hpb=977a33f0978bec21b3c12a8c04a40bf56afe7334;p=umurmur.git diff --git a/src/client.c b/src/client.c index e4936e2..a992129 100644 --- a/src/client.c +++ b/src/client.c @@ -1,5 +1,5 @@ -/* Copyright (C) 2009-2011, Martin Johansson - Copyright (C) 2005-2011, Thorvald Natvig +/* Copyright (C) 2009-2012, Martin Johansson + Copyright (C) 2005-2012, Thorvald Natvig All rights reserved. @@ -45,6 +45,7 @@ #include "channel.h" #include "version.h" #include "voicetarget.h" +#include "ban.h" extern char system_string[], version_string[]; @@ -56,6 +57,7 @@ void Client_free(client_t *client); declare_list(clients); static int clientcount; /* = 0 */ static int maxBandwidth; +bool_t bOpus = true; int iCodecAlpha, iCodecBeta; bool_t bPreferAlpha; @@ -90,9 +92,9 @@ int Client_getfds(struct pollfd *pollfds) void Client_janitor() { - struct dlist *itr; + struct dlist *itr, *save; int bwTop = maxBandwidth + maxBandwidth / 4; - list_iterate(itr, &clients) { + list_iterate_safe(itr, save, &clients) { client_t *c; c = list_get_entry(itr, client_t, node); Log_debug("Client %s BW available %d", c->username, c->availableBandwidth); @@ -100,12 +102,13 @@ void Client_janitor() if (c->availableBandwidth > bwTop) c->availableBandwidth = bwTop; - if (Timer_isElapsed(&c->lastActivity, 1000000LL * INACTICITY_TIMEOUT)) { + if (Timer_isElapsed(&c->lastActivity, 1000000LL * INACTIVITY_TIMEOUT)) { /* No activity from client - assume it is lost and close. */ Log_info_client(c, "Timeout, closing."); Client_free(c); } } + Ban_pruneBanned(); } void Client_codec_add(client_t *client, int codec) @@ -192,21 +195,28 @@ void Client_token_free(client_t *client) client->tokencount = 0; } -void recheckCodecVersions() + +#define OPUS_WARN_USING "WARNING: Your client doesn't support the Opus codec the server is using, you won't be able to talk or hear anyone. Please upgrade your Mumble client." +#define OPUS_WARN_SWITCHING "WARNING: Your client doesn't support the Opus codec the server is switching to, you won't be able to talk or hear anyone. Please upgrade your Mumble client." +void recheckCodecVersions(client_t *connectingClient) { client_t *client_itr = NULL; int max = 0, version, current_version; + int users = 0, opus = 0; message_t *sendmsg; struct dlist codec_list, *itr, *save; codec_t *codec_itr, *cd; bool_t found; - + bool_t enableOpus; + init_list_entry(&codec_list); while (Client_iterate(&client_itr) != NULL) { codec_itr = NULL; + if (client_itr->codec_count == 0 && !client_itr->bOpus) + continue; while (Client_codec_iterate(client_itr, &codec_itr) != NULL) { - found = false; + found = false; list_iterate(itr, &codec_list) { cd = list_get_entry(itr, codec_t, node); if (cd->codec == codec_itr->codec) { @@ -225,8 +235,15 @@ void recheckCodecVersions() list_add_tail(&cd->node, &codec_list); } } + users++; + if (client_itr->bOpus) + opus++; } - + if (users == 0) + return; + + enableOpus = ((opus * 100 / users) >= getIntConf(OPUS_THRESHOLD)); + list_iterate(itr, &codec_list) { cd = list_get_entry(itr, codec_t, node); if (cd->count > max) { @@ -238,33 +255,49 @@ void recheckCodecVersions() list_del(&list_get_entry(itr, codec_t, node)->node); free(list_get_entry(itr, codec_t, node)); } - + current_version = bPreferAlpha ? iCodecAlpha : iCodecBeta; - if (current_version == version) + if (current_version != version) { + // If we don't already use the compat bitstream version set + // it as alpha and announce it. If another codec now got the + // majority set it as the opposite of the currently valid bPreferAlpha + // and announce it. + if (version == (uint32_t)0x8000000b) + bPreferAlpha = true; + else + bPreferAlpha = !bPreferAlpha; + + if (bPreferAlpha) + iCodecAlpha = version; + else + iCodecBeta = version; + } else if (bOpus && enableOpus) { + if (connectingClient && !connectingClient->bOpus) + Client_textmessage(connectingClient, OPUS_WARN_USING); return; - // If we don't already use the compat bitstream version set - // it as alpha and announce it. If another codec now got the - // majority set it as the opposite of the currently valid bPreferAlpha - // and announce it. - if (version == (uint32_t)0x8000000b) - bPreferAlpha = true; - else - bPreferAlpha = ! bPreferAlpha; + } - if (bPreferAlpha) - iCodecAlpha = version; - else - iCodecBeta = version; - sendmsg = Msg_create(CodecVersion); sendmsg->payload.codecVersion->alpha = iCodecAlpha; sendmsg->payload.codecVersion->beta = iCodecBeta; sendmsg->payload.codecVersion->prefer_alpha = bPreferAlpha; + sendmsg->payload.codecVersion->has_opus = true; + sendmsg->payload.codecVersion->opus = enableOpus; + Client_send_message_except(NULL, sendmsg); - Log_info("CELT codec switch 0x%x 0x%x (prefer 0x%x)", iCodecAlpha, iCodecBeta, - bPreferAlpha ? iCodecAlpha : iCodecBeta); + if (enableOpus && !bOpus) { + client_itr = NULL; + while (Client_iterate(&client_itr) != NULL) { + if ((client_itr->authenticated || client_itr == connectingClient) && + !client_itr->bOpus) { + Client_textmessage(client_itr, OPUS_WARN_SWITCHING); + } + } + Log_info("OPUS codec %s", bOpus ? "enabled" : "disabled"); + } + bOpus = enableOpus; } static int findFreeSessionId() @@ -288,7 +321,11 @@ int Client_add(int fd, struct sockaddr_in *remote) { client_t *newclient; message_t *sendmsg; - + + if (Ban_isBannedAddr((in_addr_t *)&remote->sin_addr)) { + Log_info("Address %s banned. Disconnecting", inet_ntoa(remote->sin_addr)); + return -1; + } newclient = malloc(sizeof(client_t)); if (newclient == NULL) Log_fatal("Out of memory"); @@ -337,6 +374,7 @@ void Client_free(client_t *client) { struct dlist *itr, *save; message_t *sendmsg; + bool_t authenticatedLeft = client->authenticated; if (client->authenticated) { int leave_id; @@ -374,6 +412,9 @@ void Client_free(client_t *client) if (client->context) free(client->context); free(client); + + if (authenticatedLeft) + recheckCodecVersions(NULL); /* Can use better codec now? */ } void Client_close(client_t *client) @@ -473,14 +514,21 @@ int Client_read(client_t *client) client->readBlockedOnWrite = true; return 0; } - else if (SSLi_get_error(client->ssl, rc) == SSLI_ERROR_ZERO_RETURN) { + else if (SSLi_get_error(client->ssl, rc) == SSLI_ERROR_ZERO_RETURN || + SSLi_get_error(client->ssl, rc) == 0) { Log_info_client(client, "Connection closed by peer"); - if (!client->shutdown_wait) - Client_close(client); + Client_close(client); } else { if (SSLi_get_error(client->ssl, rc) == SSLI_ERROR_SYSCALL) { - Log_info_client(client, "Connection closed by peer"); + if (errno == 0) + Log_info_client(client, "Connection closed by peer"); + else + Log_info_client(client,"Error: %s - Closing connection (code %d)", + strerror(errno)); + } + else if (SSLi_get_error(client->ssl, rc) == SSLI_ERROR_CONNRESET) { + Log_info_client(client, "Connection reset by peer"); } else { Log_info_client(client, "SSL error: %d - Closing connection", SSLi_get_error(client->ssl, rc)); @@ -535,10 +583,15 @@ int Client_write(client_t *client) return 0; } else { - if (SSLi_get_error(client->ssl, rc) == SSLI_ERROR_SYSCALL) - Log_warn("Client_write: Error: %s - Closing connection", strerror(errno)); - else - Log_warn("Client_write: SSL error: %d - Closing connection.", SSLi_get_error(client->ssl, rc)); + if (SSLi_get_error(client->ssl, rc) == SSLI_ERROR_SYSCALL) { + Log_info_client(client, "Error: %s - Closing connection", strerror(errno)); + } + else if (SSLi_get_error(client->ssl, rc) == SSLI_ERROR_CONNRESET) { + Log_info_client(client, "Connection reset by peer"); + } + else { + Log_info_client(client, "SSL error: %d - Closing connection.", SSLi_get_error(client->ssl, rc)); + } Client_free(client); return -1; } @@ -610,6 +663,27 @@ client_t *Client_iterate(client_t **client_itr) return c; } +void Client_textmessage(client_t *client, char *text) +{ + char *message; + uint32_t *tree_id; + message_t *sendmsg = NULL; + + message = malloc(strlen(text) + 1); + if (!message) + Log_fatal("Out of memory"); + tree_id = malloc(sizeof(uint32_t)); + if (!tree_id) + Log_fatal("Out of memory"); + *tree_id = 0; + sendmsg = Msg_create(TextMessage); + sendmsg->payload.textMessage->message = message; + sendmsg->payload.textMessage->n_tree_id = 1; + sendmsg->payload.textMessage->tree_id = tree_id; + strcpy(message, text); + Client_send_message(client, sendmsg); +} + int Client_send_message_except(client_t *client, message_t *msg) { @@ -752,6 +826,9 @@ int Client_read_udp() case UDPVoiceSpeex: case UDPVoiceCELTAlpha: case UDPVoiceCELTBeta: + if (bOpus) + break; + case UDPVoiceOpus: Client_voiceMsg(itr, buffer, len); break; case UDPPing: @@ -769,7 +846,7 @@ out: static inline void Client_send_voice(client_t *src, client_t *dst, uint8_t *data, int len, int poslen) { - if (IS_AUTH(dst) && dst != src && !dst->deaf) { + if (IS_AUTH(dst) && dst != src && !dst->deaf && !dst->self_deaf) { if (poslen > 0 && /* Has positional data */ src->context != NULL && dst->context != NULL && /* ...both source and destination has context */ strcmp(src->context, dst->context) == 0) /* ...and the contexts match */ @@ -787,14 +864,14 @@ int Client_voiceMsg(client_t *client, uint8_t *data, int len) pds_t *pds = Pds_create(buffer + 1, UDP_PACKET_SIZE - 1); unsigned int type = data[0] & 0xe0; unsigned int target = data[0] & 0x1f; - unsigned int poslen, counter; + unsigned int poslen, counter, size; int offset, packetsize; voicetarget_t *vt; channel_t *ch = (channel_t *)client->channel; struct dlist *itr; - if (!client->authenticated || client->mute) + if (!client->authenticated || client->mute || client->self_mute) goto out; packetsize = 20 + 8 + 4 + len; @@ -803,13 +880,19 @@ int Client_voiceMsg(client_t *client, uint8_t *data, int len) client->availableBandwidth -= packetsize; Timer_restart(&client->idleTime); + Timer_restart(&client->lastActivity); - counter = Pds_get_numval(pdi); /* step past session id */ - do { - counter = Pds_next8(pdi); - offset = Pds_skip(pdi, counter & 0x7f); - } while ((counter & 0x80) && offset > 0); - + if ((type >> 5) != UDPVoiceOpus) { + counter = Pds_get_numval(pdi); /* step past session id */ + do { + counter = Pds_next8(pdi); + offset = Pds_skip(pdi, counter & 0x7f); + } while ((counter & 0x80) && offset > 0); + } else { + size = Pds_get_numval(pdi); + Pds_skip(pdi, size & 0x1fff); + } + poslen = pdi->maxsize - pdi->offset; /* For stripping of positional info */ Pds_add_numval(pds, client->sessionId);