changeset 21467:3d70e3ec8a47

My changes to disable external port mapping exposed a flaw where the server socket was being closed immediately, before the client had read all the data - this caused the client to receive a RST and consequently error. The solution is to wait for the client to close the connection before closing the server connection. I'm surprised this hasn't been a problem elsewhere - it seems like it would be.
author Daniel Atallah <daniel.atallah@gmail.com>
date Tue, 13 Nov 2007 06:27:27 +0000
parents 7a05b6f84545
children 94b3275eafcc
files libpurple/protocols/bonjour/bonjour_ft.c
diffstat 1 files changed, 41 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/libpurple/protocols/bonjour/bonjour_ft.c	Tue Nov 13 04:29:06 2007 +0000
+++ b/libpurple/protocols/bonjour/bonjour_ft.c	Tue Nov 13 06:27:27 2007 +0000
@@ -96,10 +96,42 @@
 	bonjour_free_xfer(xfer);
 }
 
+struct socket_cleanup {
+	int fd;
+	guint handle;
+};
+
+static void
+_wait_for_socket_close(gpointer data, gint source, PurpleInputCondition cond)
+{
+	struct socket_cleanup *sc = data;
+	char buf[1];
+	int ret;
+
+	ret = recv(source, buf, 1, 0);
+
+	if (ret == 0 || (ret == -1 && !(errno == EAGAIN || errno == EWOULDBLOCK))) {
+		purple_debug_info("bonjour", "Client completed recieving; closing server socket.\n");
+		purple_input_remove(sc->handle);
+		close(sc->fd);
+		g_free(sc);
+	}
+}
 
 static void bonjour_xfer_end(PurpleXfer *xfer)
 {
 	purple_debug_info("bonjour", "Bonjour-xfer-end.\n");
+
+	/* We can't allow the server side to close the connection until the client is complete,
+	 * otherwise there is a RST resulting in an error on the client side */
+	if (purple_xfer_get_type(xfer) == PURPLE_XFER_SEND && purple_xfer_is_completed(xfer)) {
+		struct socket_cleanup *sc = g_new0(struct socket_cleanup, 1);
+		sc->fd = xfer->fd;
+		xfer->fd = -1;
+		sc->handle = purple_input_add(sc->fd, PURPLE_INPUT_READ,
+						 _wait_for_socket_close, sc);
+	}
+
 	bonjour_free_xfer(xfer);
 }
 
@@ -568,6 +600,8 @@
 	if(xf == NULL)
 		return;
 
+	purple_debug_info("bonjour", "bonjour_sock5_request_cb - req_state = 0x%x\n", xf->sock5_req_state);
+
 	switch(xf->sock5_req_state){
 	case 0x00:
 		acceptfd = accept(source, NULL, 0);
@@ -576,7 +610,13 @@
 		} else if(acceptfd == -1) {
 
 		} else {
-			purple_debug_info("bonjour", "Conjour-sock5-request-cb. state= %d, accept=%d\n", xf->sock5_req_state, acceptfd);
+			int flags;
+
+			purple_debug_info("bonjour", "Accepted SOCKS5 ft connection - fd=%d\n", acceptfd);
+
+			flags = fcntl(acceptfd, F_GETFL);
+			fcntl(acceptfd, F_SETFL, flags | O_NONBLOCK);
+
 			purple_input_remove(xfer->watcher);
 			close(source);
 			xfer->watcher = purple_input_add(acceptfd, PURPLE_INPUT_READ,