/pidgin/main: df9f5de00ea2: PurpleSocket: fix a crash
Tomasz Wasilczyk
twasilczyk at pidgin.im
Tue May 20 05:57:29 EDT 2014
Changeset: df9f5de00ea2c33924e95d907f60c8ea32efdb05
Author: Tomasz Wasilczyk <twasilczyk at pidgin.im>
Date: 2014-05-20 11:57 +0200
Branch: default
URL: https://hg.pidgin.im/pidgin/main/rev/df9f5de00ea2
Description:
PurpleSocket: fix a crash
diffstat:
libpurple/connection.c | 11 +++++
libpurple/connection.h | 11 +++++
libpurple/core.c | 2 +
libpurple/internal.h | 25 +++++++++++
libpurple/protocols/gg/tcpsocket.c | 2 +
libpurple/purple-socket.c | 81 ++++++++++++++++++++++++++++++++++---
6 files changed, 125 insertions(+), 7 deletions(-)
diffs (240 lines):
diff --git a/libpurple/connection.c b/libpurple/connection.c
--- a/libpurple/connection.c
+++ b/libpurple/connection.c
@@ -313,6 +313,16 @@ purple_connection_get_flags(const Purple
return priv->flags;
}
+gboolean
+purple_connection_is_disconnecting(const PurpleConnection *gc)
+{
+ PurpleConnectionPrivate *priv = PURPLE_CONNECTION_GET_PRIVATE(gc);
+
+ g_return_val_if_fail(priv != NULL, TRUE);
+
+ return priv->is_finalizing;
+}
+
PurpleAccount *
purple_connection_get_account(const PurpleConnection *gc)
{
@@ -795,6 +805,7 @@ purple_connection_finalize(GObject *obje
}
purple_http_conn_cancel_all(gc);
+ _purple_socket_cancel_with_connection(gc);
purple_proxy_connect_cancel_with_handle(gc);
connections = g_list_remove(connections, gc);
diff --git a/libpurple/connection.h b/libpurple/connection.h
--- a/libpurple/connection.h
+++ b/libpurple/connection.h
@@ -377,6 +377,17 @@ PurpleConnectionFlags purple_connection_
(purple_connection_get_state(gc) == PURPLE_CONNECTION_CONNECTED)
/**
+ * purple_connection_is_disconnecting:
+ * @param gc The connection.
+ *
+ * Checks, if connection is in disconnecting state.
+ *
+ * Returns: %TRUE, if the account is disconnecting.
+ */
+gboolean
+purple_connection_is_disconnecting(const PurpleConnection *gc);
+
+/**
* purple_connection_get_account:
* @gc: The connection.
*
diff --git a/libpurple/core.c b/libpurple/core.c
--- a/libpurple/core.c
+++ b/libpurple/core.c
@@ -196,6 +196,7 @@ purple_core_init(const char *ui)
purple_log_init();
purple_network_init();
purple_pounces_init();
+ _purple_socket_init();
purple_proxy_init();
purple_dnsquery_init();
purple_sound_init();
@@ -277,6 +278,7 @@ purple_core_quit(void)
purple_theme_manager_uninit();
purple_xfers_uninit();
purple_proxy_uninit();
+ _purple_socket_uninit();
purple_dnsquery_uninit();
_purple_image_store_uninit();
purple_network_uninit();
diff --git a/libpurple/internal.h b/libpurple/internal.h
--- a/libpurple/internal.h
+++ b/libpurple/internal.h
@@ -365,4 +365,29 @@ gboolean
int
_purple_fstat(int fd, GStatBuf *st);
+/**
+ * _purple_socket_cancel_with_connection:
+ * @gc The connection.
+ *
+ * Cancels all #PurpleSocket instances bound with @gc.
+ */
+void
+_purple_socket_cancel_with_connection(PurpleConnection *gc);
+
+/**
+ * _purple_socket_init: (skip)
+ *
+ * Initializes the #PurpleSocket subsystem.
+ */
+void
+_purple_socket_init(void);
+
+/**
+ * _purple_socket_uninit: (skip)
+ *
+ * Uninitializes the #PurpleSocket subsystem.
+ */
+void
+_purple_socket_uninit(void);
+
#endif /* _PURPLE_INTERNAL_H_ */
diff --git a/libpurple/protocols/gg/tcpsocket.c b/libpurple/protocols/gg/tcpsocket.c
--- a/libpurple/protocols/gg/tcpsocket.c
+++ b/libpurple/protocols/gg/tcpsocket.c
@@ -65,6 +65,8 @@ ggp_tcpsocket_connect(void *_gc, const c
PurpleConnection *gc = _gc;
PurpleSocket *ps;
+ g_return_val_if_fail(!purple_connection_is_disconnecting(gc), NULL);
+
g_return_val_if_fail(host != NULL, NULL);
g_return_val_if_fail(is_async, NULL);
diff --git a/libpurple/purple-socket.c b/libpurple/purple-socket.c
--- a/libpurple/purple-socket.c
+++ b/libpurple/purple-socket.c
@@ -53,6 +53,43 @@ struct _PurpleSocket
gpointer cb_data;
};
+static GHashTable *handles = NULL;
+
+static void
+handle_add(PurpleSocket *ps)
+{
+ PurpleConnection *gc = ps->gc;
+ GSList *l;
+
+ l = g_hash_table_lookup(handles, gc);
+ l = g_slist_prepend(l, ps);
+ g_hash_table_insert(handles, gc, l);
+}
+
+static void
+handle_remove(PurpleSocket *ps)
+{
+ PurpleConnection *gc = ps->gc;
+ GSList *l;
+
+ l = g_hash_table_lookup(handles, gc);
+ l = g_slist_remove(l, ps);
+ g_hash_table_insert(handles, gc, l);
+}
+
+void
+_purple_socket_init(void)
+{
+ handles = g_hash_table_new(g_direct_hash, g_direct_equal);
+}
+
+void
+_purple_socket_uninit(void)
+{
+ g_hash_table_destroy(handles);
+ handles = NULL;
+}
+
PurpleSocket *
purple_socket_new(PurpleConnection *gc)
{
@@ -63,6 +100,8 @@ purple_socket_new(PurpleConnection *gc)
ps->port = -1;
ps->data = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
+ handle_add(ps);
+
return ps;
}
@@ -197,6 +236,12 @@ purple_socket_connect(PurpleSocket *ps,
g_return_val_if_fail(ps != NULL, FALSE);
+ if (ps->gc && purple_connection_is_disconnecting(ps->gc)) {
+ purple_debug_error("socket", "connection is being destroyed");
+ ps->state = PURPLE_SOCKET_STATE_ERROR;
+ return FALSE;
+ }
+
if (!purple_socket_check_state(ps, PURPLE_SOCKET_STATE_DISCONNECTED))
return FALSE;
ps->state = PURPLE_SOCKET_STATE_CONNECTING;
@@ -321,14 +366,9 @@ purple_socket_get_data(PurpleSocket *ps,
return g_hash_table_lookup(ps->data, key);
}
-void
-purple_socket_destroy(PurpleSocket *ps)
+static void
+purple_socket_cancel(PurpleSocket *ps)
{
- if (ps == NULL)
- return;
-
- g_free(ps->host);
-
if (ps->inpa > 0)
purple_input_remove(ps->inpa);
ps->inpa = 0;
@@ -337,13 +377,40 @@ purple_socket_destroy(PurpleSocket *ps)
purple_ssl_close(ps->tls_connection);
ps->fd = -1;
}
+ ps->tls_connection = NULL;
if (ps->raw_connection != NULL)
purple_proxy_connect_cancel(ps->raw_connection);
+ ps->raw_connection = NULL;
if (ps->fd > 0)
close(ps->fd);
+ ps->fd = 0;
+}
+void
+purple_socket_destroy(PurpleSocket *ps)
+{
+ if (ps == NULL)
+ return;
+
+ handle_remove(ps);
+
+ purple_socket_cancel(ps);
+
+ g_free(ps->host);
g_hash_table_destroy(ps->data);
g_free(ps);
}
+
+void
+_purple_socket_cancel_with_connection(PurpleConnection *gc)
+{
+ GSList *it;
+
+ it = g_hash_table_lookup(handles, gc);
+ for (; it; it = g_slist_next(it)) {
+ PurpleSocket *ps = it->data;
+ purple_socket_cancel(ps);
+ }
+}
More information about the Commits
mailing list