comparison libpurple/protocols/bonjour/bonjour_ft.c @ 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 dc703f13449a
comparison
equal deleted inserted replaced
21466:7a05b6f84545 21467:3d70e3ec8a47
94 { 94 {
95 purple_debug_info("bonjour", "Bonjour-xfer-cancel-recv.\n"); 95 purple_debug_info("bonjour", "Bonjour-xfer-cancel-recv.\n");
96 bonjour_free_xfer(xfer); 96 bonjour_free_xfer(xfer);
97 } 97 }
98 98
99 struct socket_cleanup {
100 int fd;
101 guint handle;
102 };
103
104 static void
105 _wait_for_socket_close(gpointer data, gint source, PurpleInputCondition cond)
106 {
107 struct socket_cleanup *sc = data;
108 char buf[1];
109 int ret;
110
111 ret = recv(source, buf, 1, 0);
112
113 if (ret == 0 || (ret == -1 && !(errno == EAGAIN || errno == EWOULDBLOCK))) {
114 purple_debug_info("bonjour", "Client completed recieving; closing server socket.\n");
115 purple_input_remove(sc->handle);
116 close(sc->fd);
117 g_free(sc);
118 }
119 }
99 120
100 static void bonjour_xfer_end(PurpleXfer *xfer) 121 static void bonjour_xfer_end(PurpleXfer *xfer)
101 { 122 {
102 purple_debug_info("bonjour", "Bonjour-xfer-end.\n"); 123 purple_debug_info("bonjour", "Bonjour-xfer-end.\n");
124
125 /* We can't allow the server side to close the connection until the client is complete,
126 * otherwise there is a RST resulting in an error on the client side */
127 if (purple_xfer_get_type(xfer) == PURPLE_XFER_SEND && purple_xfer_is_completed(xfer)) {
128 struct socket_cleanup *sc = g_new0(struct socket_cleanup, 1);
129 sc->fd = xfer->fd;
130 xfer->fd = -1;
131 sc->handle = purple_input_add(sc->fd, PURPLE_INPUT_READ,
132 _wait_for_socket_close, sc);
133 }
134
103 bonjour_free_xfer(xfer); 135 bonjour_free_xfer(xfer);
104 } 136 }
105 137
106 static PurpleXfer* 138 static PurpleXfer*
107 bonjour_si_xfer_find(BonjourData *bd, const char *sid, const char *from) 139 bonjour_si_xfer_find(BonjourData *bd, const char *sid, const char *from)
566 598
567 xf = xfer->data; 599 xf = xfer->data;
568 if(xf == NULL) 600 if(xf == NULL)
569 return; 601 return;
570 602
603 purple_debug_info("bonjour", "bonjour_sock5_request_cb - req_state = 0x%x\n", xf->sock5_req_state);
604
571 switch(xf->sock5_req_state){ 605 switch(xf->sock5_req_state){
572 case 0x00: 606 case 0x00:
573 acceptfd = accept(source, NULL, 0); 607 acceptfd = accept(source, NULL, 0);
574 if(acceptfd == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) { 608 if(acceptfd == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
575 609
576 } else if(acceptfd == -1) { 610 } else if(acceptfd == -1) {
577 611
578 } else { 612 } else {
579 purple_debug_info("bonjour", "Conjour-sock5-request-cb. state= %d, accept=%d\n", xf->sock5_req_state, acceptfd); 613 int flags;
614
615 purple_debug_info("bonjour", "Accepted SOCKS5 ft connection - fd=%d\n", acceptfd);
616
617 flags = fcntl(acceptfd, F_GETFL);
618 fcntl(acceptfd, F_SETFL, flags | O_NONBLOCK);
619
580 purple_input_remove(xfer->watcher); 620 purple_input_remove(xfer->watcher);
581 close(source); 621 close(source);
582 xfer->watcher = purple_input_add(acceptfd, PURPLE_INPUT_READ, 622 xfer->watcher = purple_input_add(acceptfd, PURPLE_INPUT_READ,
583 bonjour_sock5_request_cb, xfer); 623 bonjour_sock5_request_cb, xfer);
584 xf->sock5_req_state++; 624 xf->sock5_req_state++;