From 5ecb0c5d0c702c77778d7f1ea9846081c40561b4 Mon Sep 17 00:00:00 2001 From: Dmitry Podgorny Date: Sat, 24 Jun 2017 02:10:03 +0300 Subject: [PATCH] conn: clear system handlers on reconnect xmpp_conn_t object can be reused with saving user's handlers. However, saving system handlers can lead to a fail during connection process. This is because old object may contain timed handlers for missed features or other handlers that would handle incoming stanzas incorrectly. --- ChangeLog | 2 ++ src/common.h | 1 + src/conn.c | 2 ++ src/handler.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 76 insertions(+) diff --git a/ChangeLog b/ChangeLog index 3022d40..047232b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,8 @@ - OpenSSL tls module disables insecure SSLv2 SSLv3 and TLSv1 - Support of handlers with the same callback function, but different userdata + - System handlers are deleted on xmpp_conn_t reconnection. Old system + handlers could cause problems - New public function xmpp_sha1_digest() 0.9.1 diff --git a/src/common.h b/src/common.h index ab06e6b..1290d72 100644 --- a/src/common.h +++ b/src/common.h @@ -266,6 +266,7 @@ void handler_add(xmpp_conn_t * const conn, const char * const name, const char * const type, void * const userdata); +void handler_system_delete_all(xmpp_conn_t *conn); /* utility functions */ void disconnect_mem_error(xmpp_conn_t * const conn); diff --git a/src/conn.c b/src/conn.c index d8e34d2..f4e19a7 100644 --- a/src/conn.c +++ b/src/conn.c @@ -1215,6 +1215,8 @@ static void _conn_reset(xmpp_conn_t * const conn) conn->secured = 0; conn->tls_failed = 0; conn->error = 0; + + handler_system_delete_all(conn); } static int _conn_connect(xmpp_conn_t * const conn, diff --git a/src/handler.c b/src/handler.c index d71646f..dc53534 100644 --- a/src/handler.c +++ b/src/handler.c @@ -87,6 +87,7 @@ void handler_fire_stanza(xmpp_conn_t * const conn, head_old = head; _handler_item_remove(&head, item); if (head != head_old) { + /* TODO implement hash_replace() */ hash_drop(conn->id_handlers, id); hash_add(conn->id_handlers, id, head); } @@ -614,3 +615,73 @@ void handler_add(xmpp_conn_t * const conn, { _handler_add(conn, handler, ns, name, type, userdata, 0); } + +/** Delete all system handlers. + * This function is used to reset conn object before re-connecting. + * + * @param conn a Strophe connection object + */ +void handler_system_delete_all(xmpp_conn_t *conn) +{ + xmpp_handlist_t *item, *next, *head, *head_old; + hash_iterator_t *iter; + const char *key; + char *key2; + + /* TODO unify all kinds of handlers and avoid copy-paste below */ + + item = conn->handlers; + while (item) { + if (!item->user_handler) { + next = item->next; + _handler_item_remove(&conn->handlers, item); + if (item->ns) xmpp_free(conn->ctx, item->ns); + if (item->name) xmpp_free(conn->ctx, item->name); + if (item->type) xmpp_free(conn->ctx, item->type); + xmpp_free(conn->ctx, item); + item = next; + } else + item = item->next; + } + + item = conn->timed_handlers; + while (item) { + if (!item->user_handler) { + next = item->next; + _handler_item_remove(&conn->timed_handlers, item); + xmpp_free(conn->ctx, item); + item = next; + } else + item = item->next; + } + + iter = hash_iter_new(conn->id_handlers); + key = iter == NULL ? NULL : hash_iter_next(iter); + while (key != NULL) { + head = head_old = (xmpp_handlist_t *)hash_get(conn->id_handlers, key); + item = head; + while (item) { + if (!item->user_handler) { + next = item->next; + _handler_item_remove(&head, item); + xmpp_free(conn->ctx, item->id); + xmpp_free(conn->ctx, item); + item = next; + } else + item = item->next; + } + if (head != head_old) + key2 = xmpp_strdup(conn->ctx, key); + /* Hash table implementation is not perfect, so we need to find next + key before dropping current one. Otherwise, we will get access to + freed memory. */ + key = hash_iter_next(iter); + if (head != head_old) { + /* TODO implement hash_replace() to reduce number of allocations */ + hash_drop(conn->id_handlers, key2); + if (head != NULL) + hash_add(conn->id_handlers, key2, head); + xmpp_free(conn->ctx, key2); + } + } +}