diff options
author | Sebastien Helleu <flashcode@flashtux.org> | 2013-02-26 21:43:39 +0100 |
---|---|---|
committer | Sebastien Helleu <flashcode@flashtux.org> | 2013-02-26 21:43:39 +0100 |
commit | e890ac0a81dba1ad9810249eb89ead63b9e53c1f (patch) | |
tree | f9c604c6409245edc651cd0970877c07536c8149 /src | |
parent | 0e641e0c45607dffd7bd4c7a9961646ea8f92392 (diff) | |
download | weechat-e890ac0a81dba1ad9810249eb89ead63b9e53c1f.zip |
xfer: fix freeze of DCC file received: use non-blocking socket after connection to sender and ensure the ACK is properly sent (bug #38340)
Diffstat (limited to 'src')
-rw-r--r-- | src/plugins/xfer/xfer-dcc.c | 33 | ||||
-rw-r--r-- | src/plugins/xfer/xfer-network.c | 5 | ||||
-rw-r--r-- | src/plugins/xfer/xfer.h | 3 |
3 files changed, 38 insertions, 3 deletions
diff --git a/src/plugins/xfer/xfer-dcc.c b/src/plugins/xfer/xfer-dcc.c index 1c12ca9b6..644518ad9 100644 --- a/src/plugins/xfer/xfer-dcc.c +++ b/src/plugins/xfer/xfer-dcc.c @@ -179,9 +179,10 @@ xfer_dcc_send_file_child (struct t_xfer *xfer) void xfer_dcc_recv_file_child (struct t_xfer *xfer) { - int num_read; + int flags, num_read, num_sent, total_sent, length; static char buffer[XFER_BLOCKSIZE_MAX]; uint32_t pos; + const void *ptr_buf; time_t last_sent, new_time; unsigned long long bytes_remaining; @@ -198,6 +199,12 @@ xfer_dcc_recv_file_child (struct t_xfer *xfer) xfer_network_write_pipe (xfer, XFER_STATUS_ACTIVE, XFER_NO_ERROR); + /* make socket non-blocking */ + flags = fcntl (xfer->sock, F_GETFL); + if (flags == -1) + flags = 0; + fcntl (xfer->sock, F_SETFL, flags | O_NONBLOCK); + last_sent = time (NULL); while (1) { @@ -236,8 +243,28 @@ xfer_dcc_recv_file_child (struct t_xfer *xfer) xfer->pos += (unsigned long long) num_read; pos = htonl (xfer->pos); - /* we don't check return code, not a problem if an ACK send failed */ - send (xfer->sock, (char *) &pos, 4, 0); + /* send the ACK (and ensure the 4 bytes are sent) */ + ptr_buf = &pos; + length = 4; + total_sent = 0; + num_sent = send (xfer->sock, ptr_buf, length, 0); + if (num_sent > 0) + total_sent += num_sent; + while (total_sent < length) + { + if ((num_sent == -1) && (errno != EAGAIN) + && (errno != EWOULDBLOCK)) + { + xfer_network_write_pipe (xfer, XFER_STATUS_FAILED, + XFER_ERROR_SEND_ACK); + return; + } + usleep (1000); + num_sent = send (xfer->sock, ptr_buf + total_sent, + length - total_sent, 0); + if (num_sent > 0) + total_sent += num_sent; + } /* file received ok? */ if (xfer->pos >= xfer->size) diff --git a/src/plugins/xfer/xfer-network.c b/src/plugins/xfer/xfer-network.c index 754e0b319..8aea10180 100644 --- a/src/plugins/xfer/xfer-network.c +++ b/src/plugins/xfer/xfer-network.c @@ -146,6 +146,11 @@ xfer_network_child_read_cb (void *arg_xfer, int fd) _("%s%s: unable to write local file"), weechat_prefix ("error"), XFER_PLUGIN_NAME); break; + case XFER_ERROR_SEND_ACK: + weechat_printf (NULL, + _("%s%s: unable to send ACK to sender"), + weechat_prefix ("error"), XFER_PLUGIN_NAME); + break; } /* read new DCC status */ diff --git a/src/plugins/xfer/xfer.h b/src/plugins/xfer/xfer.h index 99de6bdc5..a0773ed24 100644 --- a/src/plugins/xfer/xfer.h +++ b/src/plugins/xfer/xfer.h @@ -66,12 +66,15 @@ enum t_xfer_status enum t_xfer_error { XFER_NO_ERROR = 0, /* no error to report, all ok! */ + /* errors for sender: */ XFER_ERROR_READ_LOCAL, /* unable to read local file */ XFER_ERROR_SEND_BLOCK, /* unable to send block to receiver */ XFER_ERROR_READ_ACK, /* unable to read ACK from receiver */ + /* errors for receiver: */ XFER_ERROR_CONNECT_SENDER, /* unable to connect to sender */ XFER_ERROR_RECV_BLOCK, /* unable to recv block from sender */ XFER_ERROR_WRITE_LOCAL, /* unable to write to local file */ + XFER_ERROR_SEND_ACK, /* unable to send ACK to sender */ /* number of errors */ XFER_NUM_ERRORS, }; |