]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
res_xmpp: Use incremental backoff when a read error occurs
authorSean Bright <sean.bright@gmail.com>
Thu, 23 Mar 2017 14:48:40 +0000 (10:48 -0400)
committerSean Bright <sean.bright@gmail.com>
Fri, 24 Mar 2017 21:10:43 +0000 (17:10 -0400)
If a read error occurs, we immediately attempt a reconnect without any
delay. Instead, let's sleep and backoff up to 60 seconds before we try
again.

ASTERISK-24712 #close
Reported by: Matthias Urlichs

Change-Id: I6fe10ef4734837727437beab715e336777f13f48

res/res_xmpp.c

index a80c2ed807d2e89c412c856a01ef70a48d7114f1..dadde98b4488033a0d171db4ea40385ab826ef32 100644 (file)
@@ -3595,6 +3595,7 @@ int ast_xmpp_client_disconnect(struct ast_xmpp_client *client)
 {
        if ((client->thread != AST_PTHREADT_NULL) && !pthread_equal(pthread_self(), client->thread)) {
                xmpp_client_change_state(client, XMPP_STATE_DISCONNECTING);
+               pthread_cancel(client->thread);
                pthread_join(client->thread, NULL);
                client->thread = AST_PTHREADT_NULL;
        }
@@ -3774,11 +3775,26 @@ static int xmpp_client_receive(struct ast_xmpp_client *client, unsigned int time
        return IKS_OK;
 }
 
+static void sleep_with_backoff(unsigned int *sleep_time)
+{
+       /* We're OK with our thread dying here */
+       pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+
+       sleep(*sleep_time);
+       *sleep_time = MIN(60, *sleep_time * 2);
+
+       pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+}
+
 /*! \brief XMPP client connection thread */
 static void *xmpp_client_thread(void *data)
 {
        struct ast_xmpp_client *client = data;
        int res = IKS_NET_RWERR;
+       unsigned int sleep_time = 1;
+
+       /* We only allow cancellation while sleeping */
+       pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
 
        do {
                if (client->state == XMPP_STATE_DISCONNECTING) {
@@ -3789,7 +3805,7 @@ static void *xmpp_client_thread(void *data)
                if (res == IKS_NET_RWERR || client->timeout == 0) {
                        ast_debug(3, "[%s] Connecting\n", client->name);
                        if ((res = xmpp_client_reconnect(client)) != IKS_OK) {
-                               sleep(4);
+                               sleep_with_backoff(&sleep_time);
                                res = IKS_NET_RWERR;
                        }
                        continue;
@@ -3828,6 +3844,8 @@ static void *xmpp_client_thread(void *data)
                        }
                } else if (res == IKS_NET_RWERR) {
                        ast_log(LOG_WARNING, "[%s] Socket read error\n", client->name);
+                       ast_xmpp_client_disconnect(client);
+                       sleep_with_backoff(&sleep_time);
                } else if (res == IKS_NET_NOSOCK) {
                        ast_log(LOG_WARNING, "[%s] No socket\n", client->name);
                } else if (res == IKS_NET_NOCONN) {
@@ -3840,6 +3858,8 @@ static void *xmpp_client_thread(void *data)
                        ast_log(LOG_WARNING, "[%s] Dropped?\n", client->name);
                } else if (res == IKS_NET_UNKNOWN) {
                        ast_debug(5, "[%s] Unknown\n", client->name);
+               } else if (res == IKS_OK) {
+                       sleep_time = 1;
                }
 
        } while (1);