1
0
mirror of https://github.com/profanity-im/profanity.git synced 2024-12-04 14:46:46 -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_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