# HG changeset patch # User Daniel Atallah # Date 1194935247 0 # Node ID 3d70e3ec8a47fd0d5b2f60f0ccf55cb5ddea545a # Parent 7a05b6f84545e55508e018a0055052acb3acf4e9 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. diff -r 7a05b6f84545 -r 3d70e3ec8a47 libpurple/protocols/bonjour/bonjour_ft.c --- 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,