cpw.darkrain42.xmpp.bosh: 8aa3507d: BOSH: Use a write buffer (read: basicall...

paul at darkrain42.org paul at darkrain42.org
Sat Apr 4 19:15:41 EDT 2009


-----------------------------------------------------------------
Revision: 8aa3507dc80559098f9ac283dd24fe367f814bee
Ancestor: 06a295e020eccbf9caabb99c59a341b531098f43
Author: paul at darkrain42.org
Date: 2009-04-04T23:05:04
Branch: im.pidgin.cpw.darkrain42.xmpp.bosh
URL: http://d.pidgin.im/viewmtn/revision/info/8aa3507dc80559098f9ac283dd24fe367f814bee

Modified files:
        libpurple/protocols/jabber/bosh.c

ChangeLog: 

BOSH: Use a write buffer (read: basically cut-n-paste from jabber.c)

-------------- next part --------------
============================================================
--- libpurple/protocols/jabber/bosh.c	63f3731f3cb0d172094d200e4053b3c6edc9ab8c
+++ libpurple/protocols/jabber/bosh.c	9edebc2942dcbb3959bf1236249890dd1bb98a94
@@ -79,8 +79,11 @@ struct _PurpleHTTPConnection {
 	PurpleBOSHConnection *bosh;
 	PurpleSslConnection *psc;
 	int fd;
-	int ie_handle;
+	guint readh;
+	guint writeh;
 
+	PurpleCircBuffer *write_buffer;
+
 	gboolean ready;
 	int requests; /* number of outstanding HTTP requests */
 
@@ -92,7 +95,8 @@ static void http_connection_connect(Purp
 };
 
 static void http_connection_connect(PurpleHTTPConnection *conn);
-static void http_connection_send_request(PurpleHTTPConnection *conn, const GString *req);
+static void http_connection_send_request(PurpleHTTPConnection *conn,
+                                         const GString *req);
 
 void jabber_bosh_init(void)
 {
@@ -127,6 +131,8 @@ jabber_bosh_http_connection_init(PurpleB
 	conn->fd = -1;
 	conn->ready = FALSE;
 
+	conn->write_buffer = purple_circ_buffer_new(0 /* default grow size */);
+
 	return conn;
 }
 
@@ -136,8 +142,12 @@ jabber_bosh_http_connection_destroy(Purp
 	if (conn->buf)
 		g_string_free(conn->buf, TRUE);
 
-	if (conn->ie_handle)
-		purple_input_remove(conn->ie_handle);
+	if (conn->write_buffer)
+		purple_circ_buffer_destroy(conn->write_buffer);
+	if (conn->readh)
+		purple_input_remove(conn->readh);
+	if (conn->writeh)
+		purple_input_remove(conn->writeh);
 	if (conn->psc)
 		purple_ssl_close(conn->psc);
 	if (conn->fd >= 0)
@@ -579,11 +589,16 @@ static void http_connection_disconnected
 		conn->fd = -1;
 	}
 
-	if (conn->ie_handle) {
-		purple_input_remove(conn->ie_handle);
-		conn->ie_handle = 0;
+	if (conn->readh) {
+		purple_input_remove(conn->readh);
+		conn->readh = 0;
 	}
 
+	if (conn->writeh) {
+		purple_input_remove(conn->writeh);
+		conn->writeh = 0;
+	}
+
 	if (conn->bosh->pipelining)
 		/* Hmmmm, fall back to multiple connections */
 		conn->bosh->pipelining = FALSE;
@@ -696,7 +711,7 @@ http_connection_read(PurpleHTTPConnectio
 
 		/*
 		 * If the socket is closed, the processing really needs to know about
-		 * it. Handle that now (it will be handled again post-processing).
+		 * it. Handle that now.
 		 */
 		http_connection_disconnected(conn);
 
@@ -762,7 +777,7 @@ connection_established_cb(gpointer data,
 	}
 
 	conn->fd = source;
-	conn->ie_handle = purple_input_add(conn->fd, PURPLE_INPUT_READ,
+	conn->readh = purple_input_add(conn->fd, PURPLE_INPUT_READ,
 	        http_connection_read_cb, conn);
 	connection_common_established_cb(conn);
 }
@@ -797,13 +812,59 @@ static void http_connection_connect(Purp
 	}
 }
 
+static int
+http_connection_do_send(PurpleHTTPConnection *conn, const char *data, int len)
+{
+	int ret;
+
+	if (conn->psc)
+		ret = purple_ssl_write(conn->psc, data, len);
+	else
+		ret = write(conn->fd, data, len);
+
+	return ret;
+}
+
 static void
+http_connection_send_cb(gpointer data, gint source, PurpleInputCondition cond)
+{
+	PurpleHTTPConnection *conn = data;
+	int ret;
+	int writelen = purple_circ_buffer_get_max_read(conn->write_buffer);
+
+	if (writelen == 0) {
+		purple_input_remove(conn->writeh);
+		conn->writeh = 0;
+		return;
+	}
+
+	ret = http_connection_do_send(conn, conn->write_buffer->outptr, writelen);
+
+	if (ret < 0 && errno == EAGAIN)
+		return;
+	else if (ret <= 0) {
+		/*
+		 * TODO: Handle this better. Probably requires a PurpleBOSHConnection
+		 * buffer that stores what is "being sent" until the
+		 * PurpleHTTPConnection reports it is fully sent.
+		 */
+		purple_connection_error_reason(conn->bosh->js->gc,
+				PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+				_("Write error"));
+		return;
+	}
+
+	purple_circ_buffer_mark_read(conn->write_buffer, ret);
+}
+
+static void
 http_connection_send_request(PurpleHTTPConnection *conn, const GString *req)
 {
-	char *packet;
+	char *data;
 	int ret;
+	size_t len;
 
-	packet = g_strdup_printf("POST %s HTTP/1.1\r\n"
+	data = g_strdup_printf("POST %s HTTP/1.1\r\n"
 	                       "Host: %s\r\n"
 	                       "User-Agent: %s\r\n"
 	                       "Content-Encoding: text/xml; charset=utf-8\r\n"
@@ -812,25 +873,35 @@ http_connection_send_request(PurpleHTTPC
 	                       conn->bosh->path, conn->bosh->host, bosh_useragent,
 	                       req->len, req->str);
 
-	/* TODO: Better error handling, circbuffer or possible integration with
-	 * low-level code in jabber.c */
-	if (conn->psc)
-		ret = purple_ssl_write(conn->psc, packet, strlen(packet));
-	else
-		ret = write(conn->fd, packet, strlen(packet));
+	len = strlen(data);
 
 	++conn->requests;
 	++conn->bosh->requests;
-	g_free(packet);
 
-	if (ret < 0 && errno == EAGAIN)
-		purple_debug_error("jabber", "BOSH write would have blocked\n");
+	if (conn->writeh == 0)
+		ret = http_connection_do_send(conn, data, len);
+	else {
+		ret = -1;
+		errno = EAGAIN;
+	}
 
-	if (ret <= 0) {
+	if (ret < 0 && errno != EAGAIN) {
+		/*
+		 * TODO: Handle this better. Probably requires a PurpleBOSHConnection
+		 * buffer that stores what is "being sent" until the
+		 * PurpleHTTPConnection reports it is fully sent.
+		 */
 		purple_connection_error_reason(conn->bosh->js->gc,
 				PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
 				_("Write error"));
 		return;
+	} else if (ret < len) {
+		if (ret < 0)
+			ret = 0;
+		if (conn->writeh == 0)
+			conn->writeh = purple_input_add(conn->psc ? conn->psc->fd : conn->fd,
+					PURPLE_INPUT_WRITE, http_connection_send_cb, conn);
+		purple_circ_buffer_append(conn->write_buffer, data + ret, len - ret);
 	}
 }
 


More information about the Commits mailing list