--- a/libpurple/protocols/bonjour/bonjour_ft.c Sat Nov 07 05:14:12 2020 -0600
+++ b/libpurple/protocols/bonjour/bonjour_ft.c Tue Nov 10 01:10:33 2020 -0600
@@ -60,6 +60,7 @@
+ GCancellable *cancellable; @@ -68,14 +69,13 @@
- PurpleProxyInfo *proxy_info;
- PurpleProxyConnectData *proxy_connection;
@@ -125,7 +125,10 @@
static void bonjour_xfer_cancel_send(PurpleXfer *xfer)
+ XepXfer *xf = XEP_XFER(xfer); purple_debug_info("bonjour", "Bonjour-xfer-cancel-send.\n");
+ g_cancellable_cancel(xf->cancellable); static void bonjour_xfer_request_denied(PurpleXfer *xfer)
@@ -141,7 +144,10 @@
static void bonjour_xfer_cancel_recv(PurpleXfer *xfer)
+ XepXfer *xf = XEP_XFER(xfer); purple_debug_info("bonjour", "Bonjour-xfer-cancel-recv.\n");
+ g_cancellable_cancel(xf->cancellable); @@ -976,29 +982,59 @@
-bonjour_bytestreams_connect_cb(gpointer data, gint source, const gchar *error_message)
+bonjour_bytestreams_handle_failure(PurpleXfer *xfer, const gchar *error_message) - PurpleXfer *xfer = data;
XepXfer *xf = XEP_XFER(xfer);
+ PurpleXmlNode *tmp_node; + purple_debug_error("bonjour", "Error connecting via SOCKS5 to %s - %s", + xf->proxy_host, error_message); + tmp_node = purple_xmlnode_get_next_twin(xf->streamhost); + ret = __xep_bytestreams_parse(xf->pb, xfer, tmp_node, xf->iq_id); + xep_ft_si_reject(xf->data, xf->iq_id, purple_xfer_get_remote_user(xfer), + /* Cancel the connection */ + purple_xfer_cancel_local(xfer); +bonjour_bytestreams_connect_cb(GObject *source, GAsyncResult *result, + PurpleXfer *xfer = PURPLE_XFER(user_data); + XepXfer *xf = XEP_XFER(xfer); PurpleXmlNode *q_node, *tmp_node;
- xf->proxy_connection = NULL;
- purple_debug_error("bonjour", "Error connecting via SOCKS5 to %s - %s\n",
- xf->proxy_host, error_message ? error_message : "(null)");
+ stream = g_proxy_connect_finish(G_PROXY(source), result, &error); + if (!g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + purple_debug_error("bonjour", + "Unable to connect to destination host: %s", + bonjour_bytestreams_handle_failure( + xfer, "Unable to connect to destination host."); - tmp_node = purple_xmlnode_get_next_twin(xf->streamhost);
- ret = __xep_bytestreams_parse(xf->pb, xfer, tmp_node, xf->iq_id);
- xep_ft_si_reject(xf->data, xf->iq_id, purple_xfer_get_remote_user(xfer), "404", "cancel");
- /* Cancel the connection */
- purple_xfer_cancel_local(xfer);
+ if (!G_IS_SOCKET_CONNECTION(stream)) { + purple_debug_error("bonjour", + "GProxy didn't return a GSocketConnection."); + bonjour_bytestreams_handle_failure( + xfer, "GProxy didn't return a GSocketConnection."); + g_object_unref(stream); @@ -1016,70 +1052,135 @@
purple_xmlnode_set_attrib(tmp_node, "jid", xf->jid);
xep_iq_send_and_free(iq);
- purple_xfer_start(xfer, source, NULL, -1);
+ xf->conn = G_SOCKET_CONNECTION(stream); + socket = g_socket_connection_get_socket(xf->conn); + purple_xfer_start(xfer, g_socket_get_fd(socket), NULL, -1); +/* This is called when we connect to the SOCKS5 proxy server (through any + * relevant account proxy) +bonjour_bytestreams_socks5_connect_to_host_cb(GObject *source, + PurpleXfer *xfer = PURPLE_XFER(user_data); + XepXfer *xf = XEP_XFER(xfer); + GSocketConnection *conn; + GInetSocketAddress *inet_addr; + GSocketAddress *proxy_addr; + conn = g_socket_client_connect_to_host_finish(G_SOCKET_CLIENT(source), + if (!g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + purple_debug_error("bonjour", + "Unable to connect to SOCKS5 host: %s", + bonjour_bytestreams_handle_failure( + xfer, "Unable to connect to SOCKS5 host."); + proxy = g_proxy_get_default_for_protocol("socks5"); + purple_debug_error("bonjour", "SOCKS5 proxy backend missing."); + bonjour_bytestreams_handle_failure(xfer, + "SOCKS5 proxy backend missing."); + addr = g_socket_connection_get_remote_address(conn, &error); + "Unable to retrieve SOCKS5 host address from connection: %s", + bonjour_bytestreams_handle_failure( + xfer, "Unable to retrieve SOCKS5 host address from connection"); + hash_input = g_strdup_printf("%s%s%s", xf->sid, purple_buddy_get_name(pb), + bonjour_get_jid(purple_buddy_get_account(pb))); + dstaddr = g_compute_checksum_for_string(G_CHECKSUM_SHA1, hash_input, -1); + purple_debug_info("bonjour", "Connecting to %s using SOCKS5 proxy %s:%d", + dstaddr, xf->proxy_host, xf->proxy_port); + inet_addr = G_INET_SOCKET_ADDRESS(addr); + g_proxy_address_new(g_inet_socket_address_get_address(inet_addr), + g_inet_socket_address_get_port(inet_addr), + "socks5", dstaddr, 0, NULL, NULL); + g_object_unref(inet_addr); + g_proxy_connect_async(proxy, G_IO_STREAM(conn), G_PROXY_ADDRESS(proxy_addr), + xf->cancellable, bonjour_bytestreams_connect_cb, + g_object_unref(proxy_addr); bonjour_bytestreams_connect(PurpleXfer *xfer)
PurpleAccount *account = NULL;
- const gchar *name = NULL;
- unsigned char hashval[20];
- purple_debug_info("bonjour", "bonjour-bytestreams-connect.\n");
+ purple_debug_info("bonjour", "bonjour-bytestreams-connect.");
- name = purple_buddy_get_name(pb);
- account = purple_buddy_get_account(pb);
- p = g_strdup_printf("%s%s%s", xf->sid, name, bonjour_get_jid(account));
+ account = purple_buddy_get_account(xf->pb); - hash = g_checksum_new(G_CHECKSUM_SHA1);
- g_checksum_update(hash, (guchar *)p, -1);
- g_checksum_get_digest(hash, hashval, &digest_len);
- memset(dstaddr, 0, 41);
- for (i = 0; i < 20; i++, p += 2) {
- g_snprintf(p, 3, "%02x", hashval[i]);
+ xf->client = purple_gio_socket_client_new(account, &error); + if (xf->client == NULL) { + /* Cancel the connection */ + purple_debug_error("bonjour", + "Failed to connect to SOCKS5 streamhost proxy: %s", + xep_ft_si_reject(xf->data, xf->iq_id, purple_xfer_get_remote_user(xfer), + purple_xfer_cancel_local(xfer); - xf->proxy_info = purple_proxy_info_new();
- purple_proxy_info_set_proxy_type(xf->proxy_info, PURPLE_PROXY_SOCKS5);
- purple_proxy_info_set_host(xf->proxy_info, xf->proxy_host);
- purple_proxy_info_set_port(xf->proxy_info, xf->proxy_port);
- xf->proxy_connection = purple_proxy_connect_socks5_account(
- purple_account_get_connection(account),
- bonjour_bytestreams_connect_cb, xfer);
+ purple_debug_info("bonjour", "Connecting to SOCKS5 proxy %s:%d", + xf->proxy_host, xf->proxy_port); - if(xf->proxy_connection == NULL) {
- xep_ft_si_reject(xf->data, xf->iq_id, purple_xfer_get_remote_user(xfer), "404", "cancel");
- /* Cancel the connection */
- purple_xfer_cancel_local(xfer);
+ g_socket_client_connect_to_host_async( + xf->client, xf->proxy_host, xf->proxy_port, xf->cancellable, + bonjour_bytestreams_socks5_connect_to_host_cb, xfer); -xep_xfer_init(XepXfer *xfer) {
+xep_xfer_init(XepXfer *xf) + xf->cancellable = g_cancellable_new(); @@ -1091,12 +1192,9 @@
bd->xfer_lists = g_slist_remove(bd->xfer_lists, PURPLE_XFER(xf));
purple_debug_misc("bonjour", "B free xfer from lists(%p).\n", bd->xfer_lists);
- if (xf->proxy_connection != NULL) {
- purple_proxy_connect_cancel(xf->proxy_connection);
- if (xf->proxy_info != NULL) {
- purple_proxy_info_destroy(xf->proxy_info);
+ g_cancellable_cancel(xf->cancellable); + g_clear_object(&xf->cancellable); + g_clear_object(&xf->client); g_socket_service_stop(xf->service);