1
0
mirror of https://github.com/profanity-im/profanity.git synced 2024-11-03 19:37:16 -05:00

xmpp/connection: fix #1103

When connection is lost, profanity tries to disconnect what leads
to an infinite loop. The loop occurs, because connection_disconnet()
runs xmpp_run_once() separately and waits for XMPP_CONN_DISCONNECT
event. But it doesn't happen, because the connection object is
disconnected.

As solution, don't disconnect after XMPP_CONN_DISCONNECT is received.
Also, don't free libstrophe objects while the event loops executes,
because the event loop continues using objects after callbacks quit.
This commit is contained in:
Dmitry Podgorny 2019-06-01 20:21:46 +03:00
parent bfa4a2ef1f
commit c2d3c3e416

View File

@ -57,7 +57,9 @@ typedef struct prof_conn_t {
xmpp_log_t *xmpp_log; xmpp_log_t *xmpp_log;
xmpp_ctx_t *xmpp_ctx; xmpp_ctx_t *xmpp_ctx;
xmpp_conn_t *xmpp_conn; xmpp_conn_t *xmpp_conn;
gboolean xmpp_in_event_loop;
jabber_conn_status_t conn_status; jabber_conn_status_t conn_status;
xmpp_conn_event_t conn_last_event;
char *presence_message; char *presence_message;
int priority; int priority;
char *domain; char *domain;
@ -85,7 +87,9 @@ connection_init(void)
xmpp_initialize(); xmpp_initialize();
conn.xmpp_conn = NULL; conn.xmpp_conn = NULL;
conn.xmpp_ctx = NULL; conn.xmpp_ctx = NULL;
conn.xmpp_in_event_loop = FALSE;
conn.conn_status = JABBER_DISCONNECTED; conn.conn_status = JABBER_DISCONNECTED;
conn.conn_last_event = XMPP_CONN_DISCONNECT;
conn.presence_message = NULL; conn.presence_message = NULL;
conn.domain = NULL; conn.domain = NULL;
conn.features_by_jid = NULL; conn.features_by_jid = NULL;
@ -96,7 +100,9 @@ connection_init(void)
void void
connection_check_events(void) connection_check_events(void)
{ {
conn.xmpp_in_event_loop = TRUE;
xmpp_run_once(conn.xmpp_ctx, 10); xmpp_run_once(conn.xmpp_ctx, 10);
conn.xmpp_in_event_loop = FALSE;
} }
void void
@ -196,21 +202,30 @@ connection_connect(const char *const jid, const char *const passwd, const char *
void void
connection_disconnect(void) connection_disconnect(void)
{ {
conn.conn_status = JABBER_DISCONNECTING; // don't disconnect already disconnected connection,
xmpp_disconnect(conn.xmpp_conn); // 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) { while (conn.conn_status == JABBER_DISCONNECTING) {
session_process_events(); session_process_events();
}
} else {
conn.conn_status = JABBER_DISCONNECTED;
} }
if (conn.xmpp_conn) { // can't free libstrophe objects while we're in the event loop
xmpp_conn_release(conn.xmpp_conn); if (!conn.xmpp_in_event_loop) {
conn.xmpp_conn = NULL; if (conn.xmpp_conn) {
} xmpp_conn_release(conn.xmpp_conn);
conn.xmpp_conn = NULL;
}
if (conn.xmpp_ctx) { if (conn.xmpp_ctx) {
xmpp_ctx_free(conn.xmpp_ctx); xmpp_ctx_free(conn.xmpp_ctx);
conn.xmpp_ctx = NULL; 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, _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) xmpp_stream_error_t *const stream_error, void *const userdata)
{ {
conn.conn_last_event = status;
switch (status) { switch (status) {
// login success // login success