pidgin/pidgin

Merged in default (pull request #617)

2019-11-04, Gary Kramlich
52c9656e40ed
Merged in default (pull request #617)

Convert XMPP stuff to GIO

Approved-by: Gary Kramlich
--- a/libpurple/network.c Sun Nov 03 09:22:21 2019 +0000
+++ b/libpurple/network.c Mon Nov 04 01:18:24 2019 +0000
@@ -150,6 +150,29 @@
return "0.0.0.0";
}
+static gchar *
+purple_network_get_local_system_ip_from_gio(GSocketConnection *sockconn)
+{
+ GSocketAddress *addr;
+ GInetSocketAddress *inetsockaddr;
+ gchar *ip;
+
+ addr = g_socket_connection_get_local_address(sockconn, NULL);
+ if ((inetsockaddr = G_INET_SOCKET_ADDRESS(addr)) != NULL) {
+ GInetAddress *inetaddr =
+ g_inet_socket_address_get_address(inetsockaddr);
+ if (g_inet_address_get_family(inetaddr) == G_SOCKET_FAMILY_IPV4 &&
+ !g_inet_address_get_is_loopback(inetaddr)) {
+ ip = g_inet_address_to_string(inetaddr);
+ g_object_unref(addr);
+ return ip;
+ }
+ }
+ g_object_unref(addr);
+
+ return g_strdup("0.0.0.0");
+}
+
GList *
purple_network_get_all_local_system_ips(void)
{
@@ -286,6 +309,42 @@
return purple_network_get_local_system_ip(fd);
}
+gchar *
+purple_network_get_my_ip_from_gio(GSocketConnection *sockconn)
+{
+ const gchar *ip = NULL;
+ PurpleStunNatDiscovery *stun;
+
+ /* Check if the user specified an IP manually */
+ if (!purple_prefs_get_bool("/purple/network/auto_ip")) {
+ ip = purple_network_get_public_ip();
+ /* Make sure the IP address entered by the user is valid */
+ if ((ip != NULL) && (purple_network_is_ipv4(ip))) {
+ return g_strdup(ip);
+ }
+ } else {
+ /* Check if STUN discovery was already done */
+ stun = purple_stun_discover(NULL);
+ if ((stun != NULL) && (stun->status == PURPLE_STUN_STATUS_DISCOVERED)) {
+ return g_strdup(stun->publicip);
+ }
+
+ /* Attempt to get the IP from a NAT device using UPnP */
+ ip = purple_upnp_get_public_ip();
+ if (ip != NULL) {
+ return g_strdup(ip);
+ }
+
+ /* Attempt to get the IP from a NAT device using NAT-PMP */
+ ip = purple_pmp_get_public_ip();
+ if (ip != NULL) {
+ return g_strdup(ip);
+ }
+ }
+
+ /* Just fetch the IP of the local system */
+ return purple_network_get_local_system_ip_from_gio(sockconn);
+}
static void
purple_network_set_upnp_port_mapping_cb(gboolean success, gpointer data)
--- a/libpurple/network.h Sun Nov 03 09:22:21 2019 +0000
+++ b/libpurple/network.h Mon Nov 04 01:18:24 2019 +0000
@@ -29,6 +29,7 @@
*/
#include <glib.h>
+#include <gio/gio.h>
G_BEGIN_DECLS
@@ -113,6 +114,23 @@
const char *purple_network_get_my_ip(int fd);
/**
+ * purple_network_get_my_ip_from_gio:
+ * @sockconn: The socket connection to use to help figure out the IP, or %NULL.
+ *
+ * Returns the IP address that should be used anywhere a
+ * public IP addresses is needed (listening for an incoming
+ * file transfer, etc).
+ *
+ * If the user has manually specified an IP address via
+ * preferences, then this IP is returned. Otherwise the
+ * IP address returned by purple_network_get_local_system_ip_from_gio()
+ * is returned.
+ *
+ * Returns: The local IP address to be used.
+ */
+gchar *purple_network_get_my_ip_from_gio(GSocketConnection *sockconn);
+
+/**
* purple_network_listen:
* @port: The port number to bind to. Must be greater than 0.
* @socket_family: The protocol family of the socket. This should be
--- a/libpurple/protocols/jabber/auth_cyrus.c Sun Nov 03 09:22:21 2019 +0000
+++ b/libpurple/protocols/jabber/auth_cyrus.c Mon Nov 04 01:18:24 2019 +0000
@@ -402,11 +402,22 @@
jabber_cyrus_start(JabberStream *js, PurpleXmlNode *mechanisms,
PurpleXmlNode **reply, char **error)
{
- PurpleXmlNode *mechnode;
+ PurpleXmlNode *mechnode, *hostname;
JabberSaslState ret;
js->sasl_mechs = g_string_new("");
js->sasl_password = g_strdup(purple_connection_get_password(js->gc));
+ /* XEP-0233 says we should grab the hostname for Kerberos v5, but there
+ * is no claim about other SASL mechanisms. Fortunately, most don't
+ * care what we use, so just use the domainpart. */
+ hostname = purple_xmlnode_get_child_with_namespace(
+ mechanisms, "hostname", NS_XMPP_SERVER_REGISTRATION);
+ if (hostname) {
+ js->serverFQDN = purple_xmlnode_get_data(hostname);
+ }
+ if (js->serverFQDN == NULL) {
+ js->serverFQDN = g_strdup(js->user->domain);
+ }
for(mechnode = purple_xmlnode_get_child(mechanisms, "mechanism"); mechnode;
mechnode = purple_xmlnode_get_next_twin(mechnode))
--- a/libpurple/protocols/jabber/bosh.c Sun Nov 03 09:22:21 2019 +0000
+++ b/libpurple/protocols/jabber/bosh.c Mon Nov 04 01:18:24 2019 +0000
@@ -134,12 +134,6 @@
conn->rid = (((guint64)g_random_int() << 32) | g_random_int());
conn->rid &= 0xFFFFFFFFFFFFFLL;
- if (g_hostname_is_ip_address(url_p->host)) {
- js->serverFQDN = g_strdup(js->user->domain);
- } else {
- js->serverFQDN = g_strdup(url_p->host);
- }
-
soup_uri_free(url_p);
g_object_unref(resolver);
--- a/libpurple/protocols/jabber/jabber.c Sun Nov 03 09:22:21 2019 +0000
+++ b/libpurple/protocols/jabber/jabber.c Mon Nov 04 01:18:24 2019 +0000
@@ -35,6 +35,7 @@
#include "proxy.h"
#include "protocol.h"
#include "purpleaccountoption.h"
+#include "purple-gio.h"
#include "request.h"
#include "server.h"
#include "status.h"
@@ -222,12 +223,13 @@
PurpleAccount *account = NULL;
PurpleXmlNode *starttls = NULL;
- /* It's a secure BOSH connection, just return FALSE and skip, without doing anything extra.
- * XEP-0206 (XMPP Over BOSH): The client SHOULD ignore any Transport Layer Security (TLS)
- * feature since BOSH channel encryption SHOULD be negotiated at the HTTP layer.
+ /* It's a secure BOSH connection, just return FALSE and skip, without doing
+ * anything extra. XEP-0206 (XMPP Over BOSH): The client SHOULD ignore any
+ * Transport Layer Security (TLS) feature since BOSH channel encryption
+ * SHOULD be negotiated at the HTTP layer.
*
- * Note: we are already receiving STARTTLS at this point from a SSL/TLS BOSH connection,
- * so it is not necessary to check if purple_ssl_is_supported().
+ * Note: we are already receiving STARTTLS at this point from a SSL/TLS BOSH
+ * connection, so it is not necessary to check if SSL is supported.
*/
if (js->bosh && jabber_bosh_connection_is_ssl(js->bosh)) {
return FALSE;
@@ -366,9 +368,10 @@
jabber_auth_handle_failure(js, *packet);
}
} else if (purple_strequal(xmlns, NS_XMPP_TLS)) {
- if (js->state != JABBER_STREAM_INITIALIZING_ENCRYPTION || js->gsc)
+ if (js->state != JABBER_STREAM_INITIALIZING_ENCRYPTION ||
+ G_IS_TLS_CONNECTION(js->stream)) {
purple_debug_warning("jabber", "Ignoring spurious %s\n", name);
- else {
+ } else {
if (purple_strequal(name, "proceed"))
tls_init(js);
/* TODO: Handle <failure/>, I guess? */
@@ -378,52 +381,27 @@
}
}
-static int jabber_do_send(JabberStream *js, const char *data, int len)
+static void
+jabber_push_bytes_cb(GObject *source, GAsyncResult *res, gpointer data)
{
- int ret;
-
- if (js->gsc)
- ret = purple_ssl_write(js->gsc, data, len);
- else
- ret = write(js->fd, data, len);
-
- return ret;
-}
-
-static void jabber_send_cb(gpointer data, gint source, PurpleInputCondition cond)
-{
+ PurpleQueuedOutputStream *stream = PURPLE_QUEUED_OUTPUT_STREAM(source);
JabberStream *js = data;
- const gchar *output = NULL;
- int ret, writelen;
-
- writelen = purple_circular_buffer_get_max_read(js->write_buffer);
- output = purple_circular_buffer_get_output(js->write_buffer);
-
- if (writelen == 0) {
- purple_input_remove(js->writeh);
- js->writeh = 0;
- return;
+ gboolean result;
+ GError *error = NULL;
+
+ result = purple_queued_output_stream_push_bytes_finish(stream, res, &error);
+
+ if (!result) {
+ purple_queued_output_stream_clear_queue(stream);
+
+ g_prefix_error(&error, "%s", _("Lost connection with server: "));
+ purple_connection_take_error(js->gc, error);
}
-
- ret = jabber_do_send(js, output, writelen);
-
- if (ret < 0 && errno == EAGAIN)
- return;
- else if (ret <= 0) {
- gchar *tmp = g_strdup_printf(_("Lost connection with server: %s"),
- g_strerror(errno));
- purple_connection_error(js->gc,
- PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp);
- g_free(tmp);
- return;
- }
-
- purple_circular_buffer_mark_read(js->write_buffer, ret);
}
static gboolean do_jabber_send_raw(JabberStream *js, const char *data, int len)
{
- int ret;
+ GBytes *output;
gboolean success = TRUE;
g_return_val_if_fail(len > 0, FALSE);
@@ -431,39 +409,11 @@
if (js->state == JABBER_STREAM_CONNECTED)
jabber_stream_restart_inactivity_timer(js);
- if (js->writeh == 0)
- ret = jabber_do_send(js, data, len);
- else {
- ret = -1;
- errno = EAGAIN;
- }
-
- if (ret < 0 && errno != EAGAIN) {
- PurpleAccount *account = purple_connection_get_account(js->gc);
- /*
- * The server may have closed the socket (on a stream error), so if
- * we're disconnecting, don't generate (possibly another) error that
- * (for some UIs) would mask the first.
- */
- if (!purple_account_is_disconnecting(account)) {
- gchar *tmp = g_strdup_printf(_("Lost connection with server: %s"),
- g_strerror(errno));
- purple_connection_error(js->gc,
- PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp);
- g_free(tmp);
- }
-
- success = FALSE;
- } else if (ret < len) {
- if (ret < 0)
- ret = 0;
- if (js->writeh == 0)
- js->writeh = purple_input_add(
- js->gsc ? js->gsc->fd : js->fd,
- PURPLE_INPUT_WRITE, jabber_send_cb, js);
- purple_circular_buffer_append(js->write_buffer,
- data + ret, len - ret);
- }
+ output = g_bytes_new(data, len);
+ purple_queued_output_stream_push_bytes_async(
+ js->output, output, G_PRIORITY_DEFAULT, js->cancellable,
+ jabber_push_bytes_cb, js);
+ g_bytes_unref(output);
return success;
}
@@ -531,8 +481,7 @@
if (js->sasl_maxbuf>0) {
int pos = 0;
- if (!js->gsc && js->fd<0)
- g_return_if_reached();
+ g_return_if_fail(js->input != NULL);
while (pos < len) {
int towrite;
@@ -647,51 +596,21 @@
}
static void
-jabber_recv_cb_ssl(gpointer data, PurpleSslConnection *gsc,
- PurpleInputCondition cond)
+jabber_recv_cb(GObject *stream, gpointer data)
{
PurpleConnection *gc = data;
JabberStream *js = purple_connection_get_protocol_data(gc);
- int len;
- static char buf[4096];
+ gssize len;
+ gchar buf[4096];
+ GError *error = NULL;
PURPLE_ASSERT_CONNECTION_IS_VALID(gc);
- while((len = purple_ssl_read(gsc, buf, sizeof(buf) - 1)) > 0) {
- purple_connection_update_last_received(gc);
- buf[len] = '\0';
- purple_debug_misc("jabber", "Recv (ssl)(%d): %s", len, buf);
- jabber_parser_process(js, buf, len);
- if(js->reinit)
- jabber_stream_init(js);
- }
-
- if(len < 0 && errno == EAGAIN)
- return;
- else {
- gchar *tmp;
- if (len == 0)
- tmp = g_strdup(_("Server closed the connection"));
- else
- tmp = g_strdup_printf(_("Lost connection with server: %s"),
- g_strerror(errno));
- purple_connection_error(js->gc,
- PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp);
- g_free(tmp);
- }
-}
-
-static void
-jabber_recv_cb(gpointer data, gint source, PurpleInputCondition condition)
-{
- PurpleConnection *gc = data;
- JabberStream *js = purple_connection_get_protocol_data(gc);
- int len;
- static char buf[4096];
-
- PURPLE_ASSERT_CONNECTION_IS_VALID(gc);
-
- if((len = read(js->fd, buf, sizeof(buf) - 1)) > 0) {
+ len = g_pollable_input_stream_read_nonblocking(
+ G_POLLABLE_INPUT_STREAM(stream), buf, sizeof(buf) - 1,
+ js->cancellable, &error);
+
+ if (len > 0) {
purple_connection_update_last_received(gc);
#ifdef HAVE_CYRUS_SASL
if (js->sasl_maxbuf > 0) {
@@ -720,43 +639,20 @@
}
#endif
buf[len] = '\0';
- purple_debug_misc("jabber", "Recv (%d): %s", len, buf);
+ purple_debug_misc("jabber", "Recv (%" G_GSSIZE_FORMAT "): %s", len,
+ buf);
jabber_parser_process(js, buf, len);
if(js->reinit)
jabber_stream_init(js);
- } else if(len < 0 && errno == EAGAIN) {
- return;
- } else {
- gchar *tmp;
- if (len == 0)
- tmp = g_strdup(_("Server closed the connection"));
- else
- tmp = g_strdup_printf(_("Lost connection with server: %s"),
- g_strerror(errno));
- purple_connection_error(js->gc,
- PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp);
- g_free(tmp);
+ } else if (len == 0) {
+ purple_connection_error(js->gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+ _("Server closed the connection"));
+ } else if (error->code != G_IO_ERROR_WOULD_BLOCK &&
+ error->code != G_IO_ERROR_CANCELLED) {
+ g_prefix_error(&error, "%s", _("Lost connection with server: "));
+ purple_connection_g_error(js->gc, error);
}
-}
-
-static void
-jabber_login_callback_ssl(gpointer data, PurpleSslConnection *gsc,
- PurpleInputCondition cond)
-{
- PurpleConnection *gc = data;
- JabberStream *js;
-
- PURPLE_ASSERT_CONNECTION_IS_VALID(gc);
-
- js = purple_connection_get_protocol_data(gc);
-
- if(js->state == JABBER_STREAM_CONNECTING)
- jabber_send_raw(js, "<?xml version='1.0' ?>", -1);
- jabber_stream_set_state(js, JABBER_STREAM_INITIALIZING);
- purple_ssl_input_add(gsc, jabber_recv_cb_ssl, gc);
-
- /* Tell the app that we're doing encryption */
- jabber_stream_set_state(js, JABBER_STREAM_INITIALIZING_ENCRYPTION);
+ g_clear_error(&error);
}
static void
@@ -823,130 +719,184 @@
}
static void
-jabber_login_callback(gpointer data, gint source, const gchar *error)
+jabber_stream_connect_finish(JabberStream *js, GIOStream *stream)
+{
+ GSource *source;
+
+ js->stream = stream;
+ js->input = g_io_stream_get_input_stream(js->stream);
+ js->output = purple_queued_output_stream_new(
+ g_io_stream_get_output_stream(js->stream));
+
+ if (js->state == JABBER_STREAM_CONNECTING) {
+ jabber_send_raw(js, "<?xml version='1.0' ?>", -1);
+ }
+
+ jabber_stream_set_state(js, JABBER_STREAM_INITIALIZING);
+ source = g_pollable_input_stream_create_source(
+ G_POLLABLE_INPUT_STREAM(js->input), js->cancellable);
+ g_source_set_callback(source, (GSourceFunc)jabber_recv_cb, js->gc, NULL);
+ js->inpa = g_source_attach(source, NULL);
+}
+
+static void
+jabber_login_callback(GObject *source_object, GAsyncResult *res, gpointer data)
{
- PurpleConnection *gc = data;
- JabberStream *js = purple_connection_get_protocol_data(gc);
-
- if (source < 0) {
- GResolver *resolver = g_resolver_get_default();
- gchar *name = g_strdup_printf("_xmppconnect.%s", js->user->domain);
-
- purple_debug_info("jabber", "Couldn't connect directly to %s. Trying to find alternative connection methods, like BOSH.\n", js->user->domain);
-
- g_resolver_lookup_records_async(resolver,
- name,
- G_RESOLVER_RECORD_TXT,
- js->cancellable,
- txt_resolved_cb,
- js);
+ GSocketClient *client = G_SOCKET_CLIENT(source_object);
+ JabberStream *js = data;
+ GSocketConnection *conn;
+ GIOStream *stream;
+ gboolean is_old_ssl = g_socket_client_get_tls(client);
+ GError *error = NULL;
+
+ conn = g_socket_client_connect_to_host_finish(client, res, &error);
+ if (conn == NULL) {
+ GResolver *resolver;
+ gchar *name;
+
+ if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+ g_error_free(error);
+ return;
+ } else if (is_old_ssl) {
+ /* Old-style SSL only makes a direct connection, or fails. */
+ purple_connection_take_error(js->gc, error);
+ return;
+ }
+ g_error_free(error);
+
+ name = g_strdup_printf("_xmppconnect.%s", js->user->domain);
+ purple_debug_info("jabber",
+ "Couldn't connect directly to %s. Trying to find "
+ "alternative connection methods, like BOSH.\n",
+ js->user->domain);
+
+ resolver = g_resolver_get_default();
+ g_resolver_lookup_records_async(resolver, name, G_RESOLVER_RECORD_TXT,
+ js->cancellable, txt_resolved_cb, js);
g_free(name);
g_object_unref(resolver);
return;
}
- js->fd = source;
-
- if(js->state == JABBER_STREAM_CONNECTING)
- jabber_send_raw(js, "<?xml version='1.0' ?>", -1);
-
- jabber_stream_set_state(js, JABBER_STREAM_INITIALIZING);
- js->inpa = purple_input_add(js->fd, PURPLE_INPUT_READ, jabber_recv_cb, gc);
+ if (is_old_ssl) {
+ stream = G_IO_STREAM(g_tcp_wrapper_connection_get_base_io_stream(
+ G_TCP_WRAPPER_CONNECTION(conn)));
+ } else {
+ stream = G_IO_STREAM(conn);
+ }
+
+ jabber_stream_connect_finish(js, stream);
+
+ if (is_old_ssl) {
+ /* Tell the app that we're doing encryption */
+ jabber_stream_set_state(js, JABBER_STREAM_INITIALIZING_ENCRYPTION);
+ }
}
static void
-jabber_ssl_connect_failure(PurpleSslConnection *gsc, PurpleSslErrorType error,
- gpointer data)
+tls_handshake_cb(GObject *source_object, GAsyncResult *res, gpointer data)
{
- PurpleConnection *gc = data;
- JabberStream *js;
-
- PURPLE_ASSERT_CONNECTION_IS_VALID(gc);
-
- js = purple_connection_get_protocol_data(gc);
- js->gsc = NULL;
-
- purple_connection_ssl_error (gc, error);
+ JabberStream *js = data;
+ GError *error = NULL;
+
+ if (!g_tls_connection_handshake_finish(G_TLS_CONNECTION(source_object), res,
+ &error)) {
+ if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+ /* Connection already closed/freed. Escape. */
+ } else if (g_error_matches(error, G_TLS_ERROR, G_TLS_ERROR_HANDSHAKE)) {
+ /* In Gio, a handshake error is because of the cert */
+ purple_connection_ssl_error(js->gc, PURPLE_SSL_CERTIFICATE_INVALID);
+ } else {
+ /* Report any other errors as handshake failing */
+ purple_connection_ssl_error(js->gc, PURPLE_SSL_HANDSHAKE_FAILED);
+ }
+
+ g_error_free(error);
+ return;
+ }
+
+ jabber_stream_connect_finish(js, js->stream);
+
+ /* Tell the app that we're doing encryption */
+ jabber_stream_set_state(js, JABBER_STREAM_INITIALIZING_ENCRYPTION);
}
static void tls_init(JabberStream *js)
{
- purple_input_remove(js->inpa);
+ GSocketConnectable *identity;
+ GIOStream *tls_conn;
+ GError *error = NULL;
+
+ g_source_remove(js->inpa);
js->inpa = 0;
- js->gsc = purple_ssl_connect_with_host_fd(purple_connection_get_account(js->gc), js->fd,
- jabber_login_callback_ssl, jabber_ssl_connect_failure, js->certificate_CN, js->gc);
- /* The fd is no longer our concern */
- js->fd = -1;
-}
-
-static gboolean jabber_login_connect(JabberStream *js, const char *domain, const char *host, int port,
- gboolean fatal_failure)
-{
- /* host should be used in preference to domain to
- * allow SASL authentication to work with FQDN of the server,
- * but we use domain as fallback for when users enter IP address
- * in connect server */
- g_free(js->serverFQDN);
- if (g_hostname_is_ip_address(host)) {
- js->serverFQDN = g_strdup(domain);
- } else {
- js->serverFQDN = g_strdup(host);
+ js->input = NULL;
+ g_filter_output_stream_set_close_base_stream(
+ G_FILTER_OUTPUT_STREAM(js->output), FALSE);
+ g_output_stream_close(G_OUTPUT_STREAM(js->output), js->cancellable, NULL);
+ js->output = NULL;
+
+ identity = g_network_address_new(js->certificate_CN, 0);
+ tls_conn = g_tls_client_connection_new(js->stream, identity, &error);
+ g_object_unref(identity);
+
+ if (tls_conn == NULL) {
+ purple_debug_warning("jabber",
+ "Error creating TLS client connection: %s",
+ error->message);
+ g_clear_error(&error);
+ purple_connection_ssl_error(js->gc, PURPLE_SSL_CONNECT_FAILED);
+ return;
}
- if (purple_proxy_connect(js->gc, purple_connection_get_account(js->gc),
- host, port, jabber_login_callback, js->gc) == NULL) {
- if (fatal_failure) {
- purple_connection_error(js->gc,
- PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
- _("Unable to connect"));
- }
-
- return FALSE;
- }
-
- return TRUE;
+ g_clear_object(&js->stream);
+ js->stream = G_IO_STREAM(tls_conn);
+
+ g_tls_connection_handshake_async(G_TLS_CONNECTION(tls_conn),
+ G_PRIORITY_DEFAULT, js->cancellable,
+ tls_handshake_cb, js);
}
static void
-srv_resolved_cb(GObject *sender, GAsyncResult *result, gpointer data)
+srv_resolved_cb(GObject *source_object, GAsyncResult *result, gpointer data)
{
- GError *error = NULL;
- GList *targets = NULL, *l = NULL;
+ GSocketClient *client = G_SOCKET_CLIENT(source_object);
JabberStream *js = data;
-
- targets = g_resolver_lookup_service_finish(G_RESOLVER(sender),
- result, &error);
- if(error) {
- purple_debug_warning("jabber",
- "SRV lookup failed, proceeding with normal connection : %s",
- error->message);
+ GSocketConnection *conn;
+ GError *error = NULL;
+
+ conn = g_socket_client_connect_to_service_finish(client, result, &error);
+ if (error) {
+ if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+ /* Do nothing; cancelled. */
+
+ } else if (g_error_matches(error, G_RESOLVER_ERROR,
+ G_RESOLVER_ERROR_NOT_FOUND)) {
+ /* If there was no response, then attempt fallback behaviour of XMPP
+ * Core 3.2.2. */
+ purple_debug_warning(
+ "jabber",
+ "SRV lookup failed, proceeding with normal connection : %s",
+ error->message);
+
+ g_socket_client_connect_to_host_async(
+ js->client, js->user->domain,
+ purple_account_get_int(
+ purple_connection_get_account(js->gc), "port",
+ 5222),
+ js->cancellable, jabber_login_callback, js);
+
+ } else {
+ /* If resolving failed or connecting failed, then just error out, as
+ * in XMPP Core 3.2.1 step 8. */
+ purple_connection_g_error(js->gc, error);
+ }
g_error_free(error);
-
- jabber_login_connect(js, js->user->domain, js->user->domain,
- purple_account_get_int(purple_connection_get_account(js->gc), "port", 5222),
- TRUE);
-
- } else {
- for(l = targets; l; l = l->next) {
- GSrvTarget *target = (GSrvTarget *)l->data;
- const gchar *hostname = g_srv_target_get_hostname(target);
- guint port = g_srv_target_get_port(target);
-
- if(jabber_login_connect(js, hostname, hostname, port, FALSE)) {
- g_resolver_free_targets(targets);
-
- return;
- }
- }
-
- g_resolver_free_targets(targets);
-
- jabber_login_connect(js, js->user->domain, js->user->domain,
- purple_account_get_int(purple_connection_get_account(js->gc), "port", 5222),
- TRUE);
+ return;
}
+
+ jabber_stream_connect_finish(js, G_IO_STREAM(conn));
}
static JabberStream *
@@ -971,7 +921,6 @@
js = g_new0(JabberStream, 1);
purple_connection_set_protocol_data(gc, js);
js->gc = gc;
- js->fd = -1;
js->http_conns = soup_session_new_with_options(SOUP_SESSION_PROXY_RESOLVER,
resolver, NULL);
g_object_unref(resolver);
@@ -1039,7 +988,6 @@
js->chats = g_hash_table_new_full(g_str_hash, g_str_equal,
g_free, (GDestroyNotify)jabber_chat_free);
js->next_id = g_random_int();
- js->write_buffer = purple_circular_buffer_new(512);
js->old_length = 0;
js->keepalive_timeout = 0;
js->max_inactivity = DEFAULT_INACTIVITY_TIME;
@@ -1071,6 +1019,7 @@
"connect_server", "");
const char *bosh_url = purple_account_get_string(account,
"bosh_url", "");
+ GError *error = NULL;
jabber_stream_set_state(js, JABBER_STREAM_CONNECTING);
@@ -1088,37 +1037,35 @@
return;
}
+ js->client = purple_gio_socket_client_new(account, &error);
+ if (js->client == NULL) {
+ purple_connection_take_error(gc, error);
+ return;
+ }
+
js->certificate_CN = g_strdup(connect_server[0] ? connect_server : js->user->domain);
/* if they've got old-ssl mode going, we probably want to ignore SRV lookups */
if (purple_strequal("old_ssl", purple_account_get_string(account, "connection_security", JABBER_DEFAULT_REQUIRE_TLS))) {
- js->gsc = purple_ssl_connect(account, js->certificate_CN,
- purple_account_get_int(account, "port", 5223),
- jabber_login_callback_ssl, jabber_ssl_connect_failure, gc);
- if (!js->gsc) {
- purple_connection_error(gc,
- PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT,
- _("Unable to establish SSL connection"));
- }
-
+ g_socket_client_set_tls(js->client, TRUE);
+ g_socket_client_connect_to_host_async(
+ js->client, js->certificate_CN,
+ purple_account_get_int(account, "port", 5223), js->cancellable,
+ jabber_login_callback, js);
return;
}
/* no old-ssl, so if they've specified a connect server, we'll use that, otherwise we'll
* invoke the magic of SRV lookups, to figure out host and port */
if(connect_server[0]) {
- jabber_login_connect(js, js->user->domain, connect_server,
- purple_account_get_int(account, "port", 5222), TRUE);
+ g_socket_client_connect_to_host_async(
+ js->client, connect_server,
+ purple_account_get_int(account, "port", 5222), js->cancellable,
+ jabber_login_callback, js);
} else {
- GResolver *resolver = g_resolver_get_default();
- g_resolver_lookup_service_async(resolver,
- "xmpp-client",
- "tcp",
- js->user->domain,
- js->cancellable,
- srv_resolved_cb,
- js);
- g_object_unref(resolver);
+ g_socket_client_connect_to_service_async(js->client, js->user->domain,
+ "xmpp-client", js->cancellable,
+ srv_resolved_cb, js);
}
}
@@ -1649,19 +1596,21 @@
if (js->bosh) {
jabber_bosh_connection_destroy(js->bosh);
js->bosh = NULL;
- } else if ((js->gsc && js->gsc->fd > 0) || js->fd > 0)
+ } else if (js->output != NULL) {
jabber_send_raw(js, "</stream:stream>", -1);
- if(js->gsc) {
- purple_ssl_close(js->gsc);
- } else if (js->fd > 0) {
if(js->inpa) {
- purple_input_remove(js->inpa);
+ g_source_remove(js->inpa);
js->inpa = 0;
}
- close(js->fd);
+ purple_gio_graceful_close(js->stream, js->input,
+ G_OUTPUT_STREAM(js->output));
}
+ g_clear_object(&js->output);
+ g_clear_object(&js->input);
+ g_clear_object(&js->stream);
+
jabber_buddy_remove_all_pending_buddy_info_requests(js);
jabber_parser_free(js);
@@ -1697,10 +1646,6 @@
g_free(js->avatar_hash);
g_free(js->caps_hash);
- if (js->write_buffer)
- g_object_unref(G_OBJECT(js->write_buffer));
- if(js->writeh)
- purple_input_remove(js->writeh);
if (js->auth_mech && js->auth_mech->dispose)
js->auth_mech->dispose(js);
#ifdef HAVE_CYRUS_SASL
@@ -1760,7 +1705,11 @@
void jabber_stream_set_state(JabberStream *js, JabberStreamState state)
{
-#define JABBER_CONNECT_STEPS ((js->gsc || js->state == JABBER_STREAM_INITIALIZING_ENCRYPTION) ? 9 : 5)
+#define JABBER_CONNECT_STEPS \
+ ((G_IS_TLS_CONNECTION(js->stream) || \
+ js->state == JABBER_STREAM_INITIALIZING_ENCRYPTION) \
+ ? 9 \
+ : 5)
js->state = state;
switch(state) {
@@ -1771,8 +1720,10 @@
JABBER_CONNECT_STEPS);
break;
case JABBER_STREAM_INITIALIZING:
- purple_connection_update_progress(js->gc, _("Initializing Stream"),
- js->gsc ? 5 : 2, JABBER_CONNECT_STEPS);
+ purple_connection_update_progress(
+ js->gc, _("Initializing Stream"),
+ G_IS_TLS_CONNECTION(js->stream) ? 5 : 2,
+ JABBER_CONNECT_STEPS);
jabber_stream_init(js);
break;
case JABBER_STREAM_INITIALIZING_ENCRYPTION:
@@ -1780,12 +1731,16 @@
6, JABBER_CONNECT_STEPS);
break;
case JABBER_STREAM_AUTHENTICATING:
- purple_connection_update_progress(js->gc, _("Authenticating"),
- js->gsc ? 7 : 3, JABBER_CONNECT_STEPS);
+ purple_connection_update_progress(
+ js->gc, _("Authenticating"),
+ G_IS_TLS_CONNECTION(js->stream) ? 7 : 3,
+ JABBER_CONNECT_STEPS);
break;
case JABBER_STREAM_POST_AUTH:
- purple_connection_update_progress(js->gc, _("Re-initializing Stream"),
- (js->gsc ? 8 : 4), JABBER_CONNECT_STEPS);
+ purple_connection_update_progress(
+ js->gc, _("Re-initializing Stream"),
+ (G_IS_TLS_CONNECTION(js->stream) ? 8 : 4),
+ JABBER_CONNECT_STEPS);
break;
case JABBER_STREAM_CONNECTED:
@@ -2109,7 +2064,7 @@
gboolean jabber_stream_is_ssl(JabberStream *js)
{
return (js->bosh && jabber_bosh_connection_is_ssl(js->bosh)) ||
- (!js->bosh && js->gsc);
+ (!js->bosh && G_IS_TLS_CONNECTION(js->stream));
}
static gboolean
--- a/libpurple/protocols/jabber/jabber.h Sun Nov 03 09:22:21 2019 +0000
+++ b/libpurple/protocols/jabber/jabber.h Mon Nov 04 01:18:24 2019 +0000
@@ -67,6 +67,7 @@
#include "media.h"
#include "mediamanager.h"
#include "protocol.h"
+#include "queuedoutputstream.h"
#include "roomlist.h"
#include "sslconn.h"
@@ -119,7 +120,6 @@
struct _JabberStream
{
- int fd;
guint inpa;
GCancellable *cancellable;
@@ -196,7 +196,10 @@
JabberBuddy *user_jb;
PurpleConnection *gc;
- PurpleSslConnection *gsc;
+ GSocketClient *client;
+ GIOStream *stream;
+ GInputStream *input;
+ PurpleQueuedOutputStream *output;
gboolean registration;
@@ -206,9 +209,6 @@
GSList *pending_buddy_info_requests;
- PurpleCircularBuffer *write_buffer;
- guint writeh;
-
gboolean reinit;
JabberCapabilities server_caps;
--- a/libpurple/protocols/jabber/namespaces.h Sun Nov 03 09:22:21 2019 +0000
+++ b/libpurple/protocols/jabber/namespaces.h Mon Nov 04 01:18:24 2019 +0000
@@ -89,6 +89,9 @@
/* XEP-0231 BoB (Bits of Binary) */
#define NS_BOB "urn:xmpp:bob"
+/* XEP-0233 XMPP Server Registration for use with Kerberos V5 */
+#define NS_XMPP_SERVER_REGISTRATION "urn:xmpp:domain-based-name:1"
+
/* XEP-0237 Roster Versioning */
#define NS_ROSTER_VERSIONING "urn:xmpp:features:rosterver"
--- a/libpurple/protocols/jabber/si.c Sun Nov 03 09:22:21 2019 +0000
+++ b/libpurple/protocols/jabber/si.c Mon Nov 04 01:18:24 2019 +0000
@@ -429,7 +429,7 @@
char buffer[42]; /* 40 for DST.ADDR + 2 bytes for port number*/
int len;
char *dstaddr, *hash;
- const char *host;
+ gchar *host;
purple_debug_info("jabber", "in jabber_si_xfer_bytestreams_send_read_again_cb\n");
@@ -508,7 +508,8 @@
g_free(dstaddr);
g_free(jsx->rxqueue);
- host = purple_network_get_my_ip(jsx->js->fd);
+ host = purple_network_get_my_ip_from_gio(
+ G_SOCKET_CONNECTION(jsx->js->stream));
jsx->rxmaxlen = 5 + strlen(host) + 2;
jsx->rxqueue = g_malloc(jsx->rxmaxlen);
@@ -527,6 +528,8 @@
jabber_si_xfer_bytestreams_send_read_again_resp_cb, xfer));
jabber_si_xfer_bytestreams_send_read_again_resp_cb(xfer, source,
PURPLE_INPUT_WRITE);
+
+ g_free(host);
}
static void
@@ -857,7 +860,7 @@
gchar *jid;
GList *local_ips =
purple_network_get_all_local_system_ips();
- const char *public_ip;
+ gchar *public_ip;
gboolean has_public_ip = FALSE;
jsx->local_streamhost_fd = sock;
@@ -867,7 +870,8 @@
purple_xfer_set_local_port(xfer, purple_network_get_port_from_fd(sock));
g_snprintf(port, sizeof(port), "%hu", purple_xfer_get_local_port(xfer));
- public_ip = purple_network_get_my_ip(jsx->js->fd);
+ public_ip = purple_network_get_my_ip_from_gio(
+ G_SOCKET_CONNECTION(jsx->js->stream));
/* Include the localhost's IPs (for in-network transfers) */
while (local_ips) {
@@ -893,6 +897,7 @@
}
g_free(jid);
+ g_free(public_ip);
/* The listener for the local proxy */
purple_xfer_set_watcher(xfer, purple_input_add(sock, PURPLE_INPUT_READ,