Update copyright year.
[umurmur.git] / src / client.c
index c3831f757fa47b42a73c6cb9d81d4471c4aedec1..9bca358d2369f0c40312d481c23d8c0675016700 100644 (file)
@@ -1,5 +1,5 @@
-/* Copyright (C) 2009-2012, Martin Johansson <martin@fatbob.nu>
-   Copyright (C) 2005-2012, Thorvald Natvig <thorvald@natvig.com>
+/* Copyright (C) 2009-2013, Martin Johansson <martin@fatbob.nu>
+   Copyright (C) 2005-2013, Thorvald Natvig <thorvald@natvig.com>
 
    All rights reserved.
 
@@ -57,7 +57,7 @@ void Client_free(client_t *client);
 declare_list(clients);
 static int clientcount; /* = 0 */
 static int maxBandwidth;
-static bool_t bOpus = true;
+bool_t bOpus = true;
 
 int iCodecAlpha, iCodecBeta;
 bool_t bPreferAlpha;
@@ -196,7 +196,8 @@ void Client_token_free(client_t *client)
 }
 
 
-#define OPUS_WARN "<strong>WARNING:</strong> Your client doesn't support the Opus codec the server is using, you won't be able to talk or hear anyone. Please upgrade"
+#define OPUS_WARN_USING "<strong>WARNING:</strong> 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 "<strong>WARNING:</strong> 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;
@@ -212,6 +213,8 @@ void recheckCodecVersions(client_t *connectingClient)
        
        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;                      
                        list_iterate(itr, &codec_list) {
@@ -231,12 +234,14 @@ void recheckCodecVersions(client_t *connectingClient)
                                cd->count = 1;
                                list_add_tail(&cd->node, &codec_list);
                        }
-                       users++;
-                       if (client_itr->bOpus)
-                               opus++;
                }
+               users++;
+               if (client_itr->bOpus)
+                       opus++;
        }
-       
+       if (users == 0) 
+               return;
+
        enableOpus = ((opus * 100 / users) >= getIntConf(OPUS_THRESHOLD));
 
        list_iterate(itr, &codec_list) {
@@ -266,41 +271,33 @@ void recheckCodecVersions(client_t *connectingClient)
                        iCodecAlpha = version;
                else
                        iCodecBeta = version;
-       } else if (bOpus == enableOpus) {
-               if (connectingClient && !connectingClient->bOpus) {
-                       char *message;
-                       uint32_t *tree_id;
-                       message_t *sendmsg = NULL;
-
-                       message = malloc(strlen(OPUS_WARN));
-                       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;
-                       sprintf(message, OPUS_WARN);
-                       Client_send_message(connectingClient, sendmsg);
-                       sendmsg = NULL;
-               }
+       } else if (bOpus && enableOpus) {
+               if (connectingClient && !connectingClient->bOpus)
+                       Client_textmessage(connectingClient, OPUS_WARN_USING);
                return;
        }
-       
-       bOpus = enableOpus;
 
        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()
@@ -377,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;
@@ -414,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)
@@ -513,14 +514,18 @@ 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,"Error: %s  - Closing connection", strerror(errno));
+                                       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");
@@ -658,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)
 {
@@ -856,8 +882,8 @@ int Client_voiceMsg(client_t *client, uint8_t *data, int len)
        Timer_restart(&client->idleTime);
        Timer_restart(&client->lastActivity);
        
+       counter = Pds_get_numval(pdi); /* step past session id */
        if ((type >> 5) != UDPVoiceOpus) {
-               counter = Pds_get_numval(pdi); /* step past session id */
                do {
                        counter = Pds_next8(pdi);
                        offset = Pds_skip(pdi, counter & 0x7f);