summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSebastien Helleu <flashcode@flashtux.org>2013-02-26 21:43:39 +0100
committerSebastien Helleu <flashcode@flashtux.org>2013-02-26 21:43:39 +0100
commite890ac0a81dba1ad9810249eb89ead63b9e53c1f (patch)
treef9c604c6409245edc651cd0970877c07536c8149 /src
parent0e641e0c45607dffd7bd4c7a9961646ea8f92392 (diff)
downloadweechat-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.c33
-rw-r--r--src/plugins/xfer/xfer-network.c5
-rw-r--r--src/plugins/xfer/xfer.h3
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,
};