about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/xmpp/connection.c39
1 files changed, 28 insertions, 11 deletions
diff --git a/src/xmpp/connection.c b/src/xmpp/connection.c
index afcd8199..62b56666 100644
--- a/src/xmpp/connection.c
+++ b/src/xmpp/connection.c
@@ -57,7 +57,9 @@ typedef struct prof_conn_t {
     xmpp_log_t *xmpp_log;
     xmpp_ctx_t *xmpp_ctx;
     xmpp_conn_t *xmpp_conn;
+    gboolean xmpp_in_event_loop;
     jabber_conn_status_t conn_status;
+    xmpp_conn_event_t conn_last_event;
     char *presence_message;
     int priority;
     char *domain;
@@ -85,7 +87,9 @@ connection_init(void)
     xmpp_initialize();
     conn.xmpp_conn = NULL;
     conn.xmpp_ctx = NULL;
+    conn.xmpp_in_event_loop = FALSE;
     conn.conn_status = JABBER_DISCONNECTED;
+    conn.conn_last_event = XMPP_CONN_DISCONNECT;
     conn.presence_message = NULL;
     conn.domain = NULL;
     conn.features_by_jid = NULL;
@@ -96,7 +100,9 @@ connection_init(void)
 void
 connection_check_events(void)
 {
+    conn.xmpp_in_event_loop = TRUE;
     xmpp_run_once(conn.xmpp_ctx, 10);
+    conn.xmpp_in_event_loop = FALSE;
 }
 
 void
@@ -196,21 +202,30 @@ connection_connect(const char *const jid, const char *const passwd, const char *
 void
 connection_disconnect(void)
 {
-    conn.conn_status = JABBER_DISCONNECTING;
-    xmpp_disconnect(conn.xmpp_conn);
+    // don't disconnect already disconnected connection,
+    // or we get infinite loop otherwise
+    if (conn.conn_last_event == XMPP_CONN_CONNECT) {
+        conn.conn_status = JABBER_DISCONNECTING;
+        xmpp_disconnect(conn.xmpp_conn);
 
-    while (conn.conn_status == JABBER_DISCONNECTING) {
-        session_process_events();
+        while (conn.conn_status == JABBER_DISCONNECTING) {
+            session_process_events();
+        }
+    } else {
+        conn.conn_status = JABBER_DISCONNECTED;
     }
 
-    if (conn.xmpp_conn) {
-        xmpp_conn_release(conn.xmpp_conn);
-        conn.xmpp_conn = NULL;
-    }
+    // can't free libstrophe objects while we're in the event loop
+    if (!conn.xmpp_in_event_loop) {
+        if (conn.xmpp_conn) {
+            xmpp_conn_release(conn.xmpp_conn);
+            conn.xmpp_conn = NULL;
+        }
 
-    if (conn.xmpp_ctx) {
-        xmpp_ctx_free(conn.xmpp_ctx);
-        conn.xmpp_ctx = NULL;
+        if (conn.xmpp_ctx) {
+            xmpp_ctx_free(conn.xmpp_ctx);
+            conn.xmpp_ctx = NULL;
+        }
     }
 }
 
@@ -470,6 +485,8 @@ static void
 _connection_handler(xmpp_conn_t *const xmpp_conn, const xmpp_conn_event_t status, const int error,
     xmpp_stream_error_t *const stream_error, void *const userdata)
 {
+    conn.conn_last_event = status;
+
     switch (status) {
 
     // login success