From 5873dfd829558cd3fdeb56f22c893b3fdc8e87c9 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Wed, 13 Feb 2002 14:04:37 +1100 Subject: [PATCH] - djm@cvs.openbsd.org 2002/02/12 12:44:46 [sftp-client.c] Let overlapped upload path handle servers which reorder ACKs. This may be permitted by the protocol spec; ok markus@ --- ChangeLog | 6 +++++- sftp-client.c | 57 +++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 53 insertions(+), 10 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6895f5267..aca92af35 100644 --- a/ChangeLog +++ b/ChangeLog @@ -20,6 +20,10 @@ [sftp.1 sftp.c sftp-client.c sftp-client.h sftp-int.c] Perform multiple overlapping read/write requests in file transfer. Mostly done by Tobias Ringstrom ; ok markus@ + - djm@cvs.openbsd.org 2002/02/12 12:44:46 + [sftp-client.c] + Let overlapped upload path handle servers which reorder ACKs. This may be + permitted by the protocol spec; ok markus@ 20020210 - (djm) OpenBSD CVS Sync @@ -7567,4 +7571,4 @@ - Wrote replacements for strlcpy and mkdtemp - Released 1.0pre1 -$Id: ChangeLog,v 1.1844 2002/02/13 03:03:56 djm Exp $ +$Id: ChangeLog,v 1.1845 2002/02/13 03:04:37 djm Exp $ diff --git a/sftp-client.c b/sftp-client.c index 835ae068a..cb11fd581 100644 --- a/sftp-client.c +++ b/sftp-client.c @@ -28,7 +28,7 @@ /* XXX: copy between two remote sites */ #include "includes.h" -RCSID("$OpenBSD: sftp-client.c,v 1.21 2002/02/12 12:32:27 djm Exp $"); +RCSID("$OpenBSD: sftp-client.c,v 1.22 2002/02/12 12:44:46 djm Exp $"); #if defined(HAVE_SYS_QUEUE_H) && !defined(HAVE_BOGUS_SYS_QUEUE_H) #include @@ -905,7 +905,7 @@ do_upload(int fd_in, int fd_out, char *local_path, char *remote_path, int pflag, size_t buflen, int num_requests) { int local_fd, status; - u_int handle_len, id; + u_int handle_len, id, type; u_int64_t offset; char *handle, *data; Buffer msg; @@ -913,6 +913,16 @@ do_upload(int fd_in, int fd_out, char *local_path, char *remote_path, Attrib a; u_int32_t startid; u_int32_t ackid; + struct outstanding_ack { + u_int id; + u_int len; + u_int64_t offset; + TAILQ_ENTRY(outstanding_ack) tq; + }; + TAILQ_HEAD(ackhead, outstanding_ack) acks; + struct outstanding_ack *ack; + + TAILQ_INIT(&acks); if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) { error("Couldn't open local file \"%s\" for reading: %s", @@ -975,21 +985,49 @@ do_upload(int fd_in, int fd_out, char *local_path, char *remote_path, strerror(errno)); if (len != 0) { + ack = xmalloc(sizeof(*ack)); + ack->id = ++id; + ack->offset = offset; + ack->len = len; + TAILQ_INSERT_TAIL(&acks, ack, tq); + buffer_clear(&msg); buffer_put_char(&msg, SSH2_FXP_WRITE); - buffer_put_int(&msg, ++id); + buffer_put_int(&msg, ack->id); buffer_put_string(&msg, handle, handle_len); buffer_put_int64(&msg, offset); buffer_put_string(&msg, data, len); send_msg(fd_out, &msg); debug3("Sent message SSH2_FXP_WRITE I:%d O:%llu S:%u", id, (u_int64_t)offset, len); - } else if ( id < ackid ) + } else if (TAILQ_FIRST(&acks) == NULL) break; - if (id == startid || len == 0 || - id - ackid >= num_requests) { - status = get_status(fd_in, ackid); + if (ack == NULL) + fatal("Unexpected ACK %u", id); + + if (id == startid || len == 0 || id - ackid >= num_requests) { + buffer_clear(&msg); + get_msg(fd_in, &msg); + type = buffer_get_char(&msg); + id = buffer_get_int(&msg); + + if (type != SSH2_FXP_STATUS) + fatal("Expected SSH2_FXP_STATUS(%d) packet, " + "got %d", SSH2_FXP_STATUS, type); + + status = buffer_get_int(&msg); + debug3("SSH2_FXP_STATUS %d", status); + + /* Find the request in our queue */ + for(ack = TAILQ_FIRST(&acks); + ack != NULL && ack->id != id; + ack = TAILQ_NEXT(ack, tq)) + ; + if (ack == NULL) + fatal("Can't find request for ID %d", id); + TAILQ_REMOVE(&acks, ack, tq); + if (status != SSH2_FX_OK) { error("Couldn't write to remote file \"%s\": %s", remote_path, fx2txt(status)); @@ -997,9 +1035,10 @@ do_upload(int fd_in, int fd_out, char *local_path, char *remote_path, close(local_fd); goto done; } - debug3("In write loop, got %d offset %llu", len, - (u_int64_t)offset); + debug3("In write loop, ack for %u %d bytes at %llu", + ack->id, ack->len, ack->offset); ++ackid; + free(ack); } offset += len;