/pidgin/main: 4523af5dc59c: irc: Port to use Gio directly for th...

Mike Ruprecht cmaiku at gmail.com
Sun May 15 11:11:27 EDT 2016


Changeset: 4523af5dc59ccbb8c622e0ddaf2bd5cf79a3e9fa
Author:	 Mike Ruprecht <cmaiku at gmail.com>
Date:	 2016-04-29 02:31 -0500
Branch:	 default
URL: https://hg.pidgin.im/pidgin/main/rev/4523af5dc59c

Description:

irc: Port to use Gio directly for the main connection

This patch ports the IRC plugin to directly use Gio for the main
connection. It uses a GSocketConnection for the main connection,
GDataInputStream for receiving data, and a PurpleQueuedOutputStream
for sending data. All of these are using their asynchronous functions.

diffstat:

 libpurple/protocols/irc/dcc_send.c |   11 +-
 libpurple/protocols/irc/irc.c      |  355 +++++++++++++-----------------------
 libpurple/protocols/irc/irc.h      |   14 +-
 3 files changed, 142 insertions(+), 238 deletions(-)

diffs (truncated from 569 to 300 lines):

diff --git a/libpurple/protocols/irc/dcc_send.c b/libpurple/protocols/irc/dcc_send.c
--- a/libpurple/protocols/irc/dcc_send.c
+++ b/libpurple/protocols/irc/dcc_send.c
@@ -279,6 +279,8 @@ irc_dccsend_network_listen_cb(int sock, 
 	struct irc_xfer_send_data *xd;
 	PurpleConnection *gc;
 	struct irc_conn *irc;
+	GSocket *gsock;
+	int fd = -1;
 	const char *arg[2];
 	char *tmp;
 	struct in_addr addr;
@@ -317,7 +319,14 @@ irc_dccsend_network_listen_cb(int sock, 
 
 	/* Send the intended recipient the DCC request */
 	arg[0] = purple_xfer_get_remote_user(xfer);
-	inet_aton(purple_network_get_my_ip(irc->fd), &addr);
+
+	/* Fetching this fd here assumes it won't be modified */
+	gsock = g_socket_connection_get_socket(irc->conn);
+	if (gsock != NULL) {
+		fd = g_socket_get_fd(gsock);
+	}
+
+	inet_aton(purple_network_get_my_ip(fd), &addr);
 	arg[1] = tmp = g_strdup_printf("\001DCC SEND \"%s\" %u %hu %" G_GOFFSET_FORMAT "\001",
 	                               purple_xfer_get_filename(xfer), ntohl(addr.s_addr),
 	                               port, purple_xfer_get_size(xfer));
diff --git a/libpurple/protocols/irc/irc.c b/libpurple/protocols/irc/irc.c
--- a/libpurple/protocols/irc/irc.c
+++ b/libpurple/protocols/irc/irc.c
@@ -32,6 +32,7 @@
 #include "notify.h"
 #include "protocol.h"
 #include "plugins.h"
+#include "tls-certificate.h"
 #include "util.h"
 #include "version.h"
 
@@ -46,15 +47,12 @@ static GList *irc_status_types(PurpleAcc
 static GList *irc_get_actions(PurpleConnection *gc);
 /* static GList *irc_chat_info(PurpleConnection *gc); */
 static void irc_login(PurpleAccount *account);
-static void irc_login_cb_ssl(gpointer data, PurpleSslConnection *gsc, PurpleInputCondition cond);
-static void irc_login_cb(gpointer data, gint source, const gchar *error_message);
-static void irc_ssl_connect_failure(PurpleSslConnection *gsc, PurpleSslErrorType error, gpointer data);
+static void irc_login_cb(GObject *source, GAsyncResult *res, gpointer user_data);
 static void irc_close(PurpleConnection *gc);
 static int irc_im_send(PurpleConnection *gc, PurpleMessage *msg);
 static int irc_chat_send(PurpleConnection *gc, int id, PurpleMessage *msg);
 static void irc_chat_join (PurpleConnection *gc, GHashTable *data);
-static void irc_input_cb(gpointer data, gint source, PurpleInputCondition cond);
-static void irc_input_cb_ssl(gpointer data, PurpleSslConnection *gsc, PurpleInputCondition cond);
+static void irc_read_input(struct irc_conn *irc);
 
 static guint irc_nick_hash(const char *nick);
 static gboolean irc_nick_equal(const char *nick1, const char *nick2);
@@ -87,19 +85,6 @@ static void irc_view_motd(PurpleProtocol
 	g_free(body);
 }
 
-static int do_send(struct irc_conn *irc, const char *buf, gsize len)
-{
-	int ret;
-
-	if (irc->gsc) {
-		ret = purple_ssl_write(irc->gsc, buf, len);
-	} else {
-		ret = write(irc->fd, buf, len);
-	}
-
-	return ret;
-}
-
 static int irc_send_raw(PurpleConnection *gc, const char *buf, int len)
 {
 	struct irc_conn *irc = purple_connection_get_protocol_data(gc);
@@ -111,44 +96,21 @@ static int irc_send_raw(PurpleConnection
 }
 
 static void
-irc_send_cb(gpointer data, gint source, PurpleInputCondition cond)
+irc_flush_cb(GObject *source, GAsyncResult *res, gpointer data)
 {
-	struct irc_conn *irc = data;
-	int ret, writelen;
-	const gchar *buffer = NULL;
+	PurpleConnection *gc = data;
+	gboolean result;
+	GError *error = NULL;
 
-	writelen = purple_circular_buffer_get_max_read(irc->outbuf);
+	result = g_output_stream_flush_finish(G_OUTPUT_STREAM(source),
+			res, &error);
 
-	if (writelen == 0) {
-		purple_input_remove(irc->writeh);
-		irc->writeh = 0;
+	if (!result) {
+		purple_connection_g_error(gc, error,
+				_("Lost connection with server: %s"));
+		g_clear_error(&error);
 		return;
 	}
-
-	buffer = purple_circular_buffer_get_output(irc->outbuf);
-
-	ret = do_send(irc, buffer, writelen);
-
-	if (ret < 0 && errno == EAGAIN)
-		return;
-	else if (ret <= 0) {
-		PurpleConnection *gc = purple_account_get_connection(irc->account);
-		gchar *tmp = g_strdup_printf(_("Lost connection with server: %s"),
-			g_strerror(errno));
-		purple_connection_error (gc,
-			PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp);
-		g_free(tmp);
-		return;
-	}
-
-	purple_circular_buffer_mark_read(irc->outbuf, ret);
-
-#if 0
-	/* We *could* try to write more if we wrote it all */
-	if (ret == write_len) {
-		irc_send_cb(data, source, cond);
-	}
-#endif
 }
 
 int irc_send(struct irc_conn *irc, const char *buf)
@@ -158,43 +120,27 @@ int irc_send(struct irc_conn *irc, const
 
 int irc_send_len(struct irc_conn *irc, const char *buf, int buflen)
 {
-	int ret;
  	char *tosend= g_strdup(buf);
+	GBytes *data;
 
 	purple_signal_emit(_irc_protocol, "irc-sending-text", purple_account_get_connection(irc->account), &tosend);
 	
 	if (tosend == NULL)
 		return 0;
 
-	/* If we're not buffering writes, try to send immediately */
-	if (!irc->writeh)
-		ret = do_send(irc, tosend, buflen);
-	else {
-		ret = -1;
-		errno = EAGAIN;
+	data = g_bytes_new_take(tosend, strlen(tosend));
+	purple_queued_output_stream_push_bytes(irc->output, data);
+	g_bytes_unref(data);
+
+	if (!g_output_stream_has_pending(G_OUTPUT_STREAM(irc->output))) {
+		/* Connection idle. Flush data. */
+		g_output_stream_flush_async(G_OUTPUT_STREAM(irc->output),
+				G_PRIORITY_DEFAULT, irc->cancellable,
+				irc_flush_cb,
+				purple_account_get_connection(irc->account));
 	}
 
-	/* purple_debug(PURPLE_DEBUG_MISC, "irc", "sent%s: %s",
-		irc->gsc ? " (ssl)" : "", tosend); */
-	if (ret <= 0 && errno != EAGAIN) {
-		PurpleConnection *gc = purple_account_get_connection(irc->account);
-		gchar *tmp = g_strdup_printf(_("Lost connection with server: %s"),
-			g_strerror(errno));
-		purple_connection_error (gc,
-			PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp);
-		g_free(tmp);
-	} else if (ret < buflen) {
-		if (ret < 0)
-			ret = 0;
-		if (!irc->writeh)
-			irc->writeh = purple_input_add(
-				irc->gsc ? irc->gsc->fd : irc->fd,
-				PURPLE_INPUT_WRITE, irc_send_cb, irc);
-		purple_circular_buffer_append(irc->outbuf, tosend + ret,
-			buflen - ret);
-	}
-	g_free(tosend);
-	return ret;
+	return strlen(tosend);
 }
 
 /* XXX I don't like messing directly with these buddies */
@@ -337,6 +283,8 @@ static void irc_login(PurpleAccount *acc
 	struct irc_conn *irc;
 	char **userparts;
 	const char *username = purple_account_get_username(account);
+	GSocketClient *client;
+	GProxyResolver *resolver;
 
 	gc = purple_account_get_connection(account);
 	purple_connection_set_flags(gc, PURPLE_CONNECTION_FLAG_NO_NEWLINES |
@@ -351,9 +299,8 @@ static void irc_login(PurpleAccount *acc
 
 	irc = g_new0(struct irc_conn, 1);
 	purple_connection_set_protocol_data(gc, irc);
-	irc->fd = -1;
 	irc->account = account;
-	irc->outbuf = purple_circular_buffer_new(512);
+	irc->cancellable = g_cancellable_new();
 
 	userparts = g_strsplit(username, "@", 2);
 	purple_connection_set_display_name(gc, userparts[0]);
@@ -369,24 +316,31 @@ static void irc_login(PurpleAccount *acc
 
 	purple_connection_update_progress(gc, _("Connecting"), 1, 2);
 
-	if (purple_account_get_bool(account, "ssl", FALSE)) {
-		irc->gsc = purple_ssl_connect(account, irc->server,
-				purple_account_get_int(account, "port", IRC_DEFAULT_SSL_PORT),
-				irc_login_cb_ssl, irc_ssl_connect_failure, gc);
+	if ((resolver = purple_proxy_get_proxy_resolver(account)) == NULL) {
+		/* Invalid proxy settings */
+		purple_connection_error (gc,
+			PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+			_("Unable to connect"));
+		return;
 	}
 
-	if (!irc->gsc) {
+	client = g_socket_client_new();
+	g_socket_client_set_proxy_resolver(client, resolver);
+	g_object_unref(resolver);
 
-		if (purple_proxy_connect(gc, account, irc->server,
-				 purple_account_get_int(account, "port", IRC_DEFAULT_PORT),
-				 irc_login_cb, gc) == NULL)
-		{
-			purple_connection_error (gc,
-				PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
-				_("Unable to connect"));
-			return;
-		}
+	/* Optionally use TLS if it's set in the account settings */
+	if (purple_account_get_bool(account, "ssl", FALSE)) {
+		g_socket_client_set_tls(client, TRUE);
+		purple_tls_certificate_attach_to_socket_client(client);
 	}
+
+	g_socket_client_connect_to_host_async(client, irc->server,
+			purple_account_get_int(account, "port",
+					g_socket_client_get_tls(client) ?
+							IRC_DEFAULT_SSL_PORT :
+							IRC_DEFAULT_PORT),
+			irc->cancellable, irc_login_cb, gc);
+	g_object_unref(client);
 }
 
 static gboolean do_login(PurpleConnection *gc) {
@@ -458,49 +412,37 @@ static gboolean do_login(PurpleConnectio
 	return TRUE;
 }
 
-static void irc_login_cb_ssl(gpointer data, PurpleSslConnection *gsc,
-	PurpleInputCondition cond)
+static void
+irc_login_cb(GObject *source, GAsyncResult *res, gpointer user_data)
 {
-	PurpleConnection *gc = data;
+	PurpleConnection *gc = user_data;
+	GSocketConnection *conn;
+	GError *error = NULL;
+	struct irc_conn *irc;
 
-	if (do_login(gc)) {
-		purple_ssl_input_add(gsc, irc_input_cb_ssl, gc);
-	}
-}
+	conn = g_socket_client_connect_to_host_finish(G_SOCKET_CLIENT(source),
+			res, &error);
 
-static void irc_login_cb(gpointer data, gint source, const gchar *error_message)
-{
-	PurpleConnection *gc = data;
-	struct irc_conn *irc = purple_connection_get_protocol_data(gc);
-
-	if (source < 0) {
-		gchar *tmp = g_strdup_printf(_("Unable to connect: %s"),
-			error_message);
-		purple_connection_error (gc,
-			PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp);
-		g_free(tmp);
+	if (conn == NULL) {
+		purple_connection_g_error(gc, error,
+				_("Unable to connect: %s"));
+		g_clear_error(&error);
 		return;
 	}
 
-	irc->fd = source;
+	irc = purple_connection_get_protocol_data(gc);
+	irc->conn = conn;
+	irc->output = purple_queued_output_stream_new(
+			g_io_stream_get_output_stream(G_IO_STREAM(irc->conn)));
 



More information about the Commits mailing list