libpurple/protocols/simple/simple.c

changeset 40422
2625e01cec7e
parent 40420
f48ae2077684
child 40423
00f2c8fb0453
--- a/libpurple/protocols/simple/simple.c	Mon May 18 19:28:04 2020 -0400
+++ b/libpurple/protocols/simple/simple.c	Mon May 18 19:58:19 2020 -0400
@@ -474,38 +474,26 @@
 
 }
 
-static void simple_canwrite_cb(gpointer data, gint source, PurpleInputCondition cond) {
-	PurpleConnection *gc = data;
-	struct simple_account_data *sip = purple_connection_get_protocol_data(gc);
-	gsize max_write;
-	gssize written;
-	const gchar *output = NULL;
+static void
+simple_push_bytes_cb(GObject *sender, GAsyncResult *res, gpointer data)
+{
+	PurpleQueuedOutputStream *stream = PURPLE_QUEUED_OUTPUT_STREAM(sender);
+	struct simple_account_data *sip = data;
+	gboolean result;
+	GError *error = NULL;
 
-	max_write = purple_circular_buffer_get_max_read(sip->txbuf);
-
-	if(max_write == 0) {
-		purple_input_remove(sip->tx_handler);
-		sip->tx_handler = 0;
-		return;
-	}
+	result = purple_queued_output_stream_push_bytes_finish(stream, res, &error);
 
-	output = purple_circular_buffer_get_output(sip->txbuf);
-
-	written = write(sip->fd, output, max_write);
+	if (!result) {
+		purple_queued_output_stream_clear_queue(stream);
 
-	if(written < 0 && errno == EAGAIN)
-		written = 0;
-	else if (written <= 0) {
-		/*TODO: do we really want to disconnect on a failure to write?*/
-		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;
+		if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+			g_error_free(error);
+		} else {
+			g_prefix_error(&error, "%s", _("Lost connection with server: "));
+			purple_connection_take_error(sip->gc, error);
+		}
 	}
-
-	purple_circular_buffer_mark_read(sip->txbuf, written);
 }
 
 static void simple_input_cb(gpointer data, gint source, PurpleInputCondition cond);
@@ -519,6 +507,7 @@
 	GSocketConnection *sockconn;
 	GSocket *socket;
 	gint fd;
+	gsize writelen;
 	GError *error = NULL;
 
 	sockconn = g_socket_client_connect_to_host_finish(G_SOCKET_CLIENT(sender),
@@ -538,14 +527,25 @@
 
 	sip = purple_connection_get_protocol_data(gc);
 	sip->fd = fd;
+	sip->output = purple_queued_output_stream_new(
+	        g_io_stream_get_output_stream(G_IO_STREAM(sockconn)));
 	sip->connecting = FALSE;
 
-	simple_canwrite_cb(gc, sip->fd, PURPLE_INPUT_WRITE);
+	writelen = purple_circular_buffer_get_max_read(sip->txbuf);
+	if (writelen != 0) {
+		const gchar *buf;
+		GBytes *output;
+
+		buf = purple_circular_buffer_get_output(sip->txbuf);
 
-	/* If there is more to write now, we need to register a handler */
-	if(purple_circular_buffer_get_used(sip->txbuf) > 0)
-		sip->tx_handler = purple_input_add(sip->fd, PURPLE_INPUT_WRITE,
-			simple_canwrite_cb, gc);
+		output = g_bytes_new(buf, writelen);
+		purple_queued_output_stream_push_bytes_async(
+		        sip->output, output, G_PRIORITY_DEFAULT, sip->cancellable,
+		        simple_push_bytes_cb, sip);
+		g_bytes_unref(output);
+
+		purple_circular_buffer_mark_read(sip->txbuf, writelen);
+	}
 
 	conn = connection_create(sip, sockconn, fd);
 	conn->inputhandler = purple_input_add(sip->fd, PURPLE_INPUT_READ, simple_input_cb, gc);
@@ -591,39 +591,18 @@
 			purple_debug_info("simple", "could not send packet\n");
 		}
 	} else {
-		int ret;
-		if(sip->fd < 0) {
+		GBytes *output;
+
+		if (sip->output == NULL) {
 			sendlater(gc, buf);
 			return;
 		}
 
-		if(sip->tx_handler) {
-			ret = -1;
-			errno = EAGAIN;
-		} else
-			ret = write(sip->fd, buf, writelen);
-
-		if (ret < 0 && errno == EAGAIN)
-			ret = 0;
-		else if(ret <= 0) { /* XXX: When does this happen legitimately? */
-			sendlater(gc, buf);
-			return;
-		}
-
-		if (ret < writelen) {
-			if(!sip->tx_handler)
-				sip->tx_handler = purple_input_add(sip->fd,
-					PURPLE_INPUT_WRITE, simple_canwrite_cb,
-					gc);
-
-			/* XXX: is it OK to do this? You might get part of a request sent
-			   with part of another. */
-			if(purple_circular_buffer_get_used(sip->txbuf) > 0)
-				purple_circular_buffer_append(sip->txbuf, "\r\n", 2);
-
-			purple_circular_buffer_append(sip->txbuf, buf + ret,
-				writelen - ret);
-		}
+		output = g_bytes_new(buf, writelen);
+		purple_queued_output_stream_push_bytes_async(
+		        sip->output, output, G_PRIORITY_DEFAULT, sip->cancellable,
+		        simple_push_bytes_cb, sip);
+		g_bytes_unref(output);
 	}
 }
 
@@ -1792,8 +1771,11 @@
 		return;
 	else if(len <= 0) {
 		purple_debug_info("simple", "simple_input_cb: read error\n");
+		if (sip->fd == source) {
+			sip->fd = -1;
+			g_clear_object(&sip->output);
+		}
 		connection_remove(sip, source);
-		if(sip->fd == source) sip->fd = -1;
 		return;
 	}
 	purple_connection_update_last_received(gc);
@@ -1855,6 +1837,8 @@
 
 	sip = purple_connection_get_protocol_data(gc);
 	sip->fd = fd;
+	sip->output = purple_queued_output_stream_new(
+	        g_io_stream_get_output_stream(G_IO_STREAM(sockconn)));
 
 	conn = connection_create(sip, sockconn, fd);
 
@@ -2128,8 +2112,6 @@
 
 	if (sip->listenpa)
 		purple_input_remove(sip->listenpa);
-	if (sip->tx_handler)
-		purple_input_remove(sip->tx_handler);
 	if (sip->resendtimeout)
 		g_source_remove(sip->resendtimeout);
 	if (sip->registertimeout)
@@ -2146,6 +2128,7 @@
 	if (sip->listen_data != NULL)
 		purple_network_listen_cancel(sip->listen_data);
 
+	g_clear_object(&sip->output);
 	if (sip->fd >= 0)
 		close(sip->fd);
 

mercurial