Mercurial > pidgin.yaz
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++; |