diff options
-rw-r--r-- | ChangeLog | 10 | ||||
-rw-r--r-- | atomicio.c | 33 | ||||
-rw-r--r-- | atomicio.h | 8 | ||||
-rw-r--r-- | misc.c | 66 | ||||
-rw-r--r-- | misc.h | 11 | ||||
-rw-r--r-- | scp.c | 122 | ||||
-rw-r--r-- | sftp-client.c | 219 | ||||
-rw-r--r-- | sftp-client.h | 4 | ||||
-rw-r--r-- | sftp.1 | 7 | ||||
-rw-r--r-- | sftp.c | 15 |
10 files changed, 282 insertions, 213 deletions
@@ -44,6 +44,16 @@ | |||
44 | ssh_config.5: format the kexalgorithms in a more consistent | 44 | ssh_config.5: format the kexalgorithms in a more consistent |
45 | (prettier!) way | 45 | (prettier!) way |
46 | ok djm | 46 | ok djm |
47 | - djm@cvs.openbsd.org 2010/09/22 22:58:51 | ||
48 | [atomicio.c atomicio.h misc.c misc.h scp.c sftp-client.c] | ||
49 | [sftp-client.h sftp.1 sftp.c] | ||
50 | add an option per-read/write callback to atomicio | ||
51 | |||
52 | factor out bandwidth limiting code from scp(1) into a generic bandwidth | ||
53 | limiter that can be attached using the atomicio callback mechanism | ||
54 | |||
55 | add a bandwidth limit option to sftp(1) using the above | ||
56 | "very nice" markus@ | ||
47 | 57 | ||
48 | 20100910 | 58 | 20100910 |
49 | - (dtucker) [openbsd-compat/port-linux.c] Check is_selinux_enabled for exact | 59 | - (dtucker) [openbsd-compat/port-linux.c] Check is_selinux_enabled for exact |
diff --git a/atomicio.c b/atomicio.c index a6b2d127a..601b3c371 100644 --- a/atomicio.c +++ b/atomicio.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: atomicio.c,v 1.25 2007/06/25 12:02:27 dtucker Exp $ */ | 1 | /* $OpenBSD: atomicio.c,v 1.26 2010/09/22 22:58:51 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2006 Damien Miller. All rights reserved. | 3 | * Copyright (c) 2006 Damien Miller. All rights reserved. |
4 | * Copyright (c) 2005 Anil Madhavapeddy. All rights reserved. | 4 | * Copyright (c) 2005 Anil Madhavapeddy. All rights reserved. |
@@ -48,7 +48,8 @@ | |||
48 | * ensure all of data on socket comes through. f==read || f==vwrite | 48 | * ensure all of data on socket comes through. f==read || f==vwrite |
49 | */ | 49 | */ |
50 | size_t | 50 | size_t |
51 | atomicio(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n) | 51 | atomicio6(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n, |
52 | int (*cb)(void *, size_t), void *cb_arg) | ||
52 | { | 53 | { |
53 | char *s = _s; | 54 | char *s = _s; |
54 | size_t pos = 0; | 55 | size_t pos = 0; |
@@ -73,17 +74,28 @@ atomicio(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n) | |||
73 | return pos; | 74 | return pos; |
74 | default: | 75 | default: |
75 | pos += (size_t)res; | 76 | pos += (size_t)res; |
77 | if (cb != NULL && cb(cb_arg, (size_t)res) == -1) { | ||
78 | errno = EINTR; | ||
79 | return pos; | ||
80 | } | ||
76 | } | 81 | } |
77 | } | 82 | } |
78 | return (pos); | 83 | return pos; |
84 | } | ||
85 | |||
86 | size_t | ||
87 | atomicio(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n) | ||
88 | { | ||
89 | return atomicio6(f, fd, _s, n, NULL, NULL); | ||
79 | } | 90 | } |
80 | 91 | ||
81 | /* | 92 | /* |
82 | * ensure all of data on socket comes through. f==readv || f==writev | 93 | * ensure all of data on socket comes through. f==readv || f==writev |
83 | */ | 94 | */ |
84 | size_t | 95 | size_t |
85 | atomiciov(ssize_t (*f) (int, const struct iovec *, int), int fd, | 96 | atomiciov6(ssize_t (*f) (int, const struct iovec *, int), int fd, |
86 | const struct iovec *_iov, int iovcnt) | 97 | const struct iovec *_iov, int iovcnt, |
98 | int (*cb)(void *, size_t), void *cb_arg) | ||
87 | { | 99 | { |
88 | size_t pos = 0, rem; | 100 | size_t pos = 0, rem; |
89 | ssize_t res; | 101 | ssize_t res; |
@@ -137,6 +149,17 @@ atomiciov(ssize_t (*f) (int, const struct iovec *, int), int fd, | |||
137 | iov[0].iov_base = ((char *)iov[0].iov_base) + rem; | 149 | iov[0].iov_base = ((char *)iov[0].iov_base) + rem; |
138 | iov[0].iov_len -= rem; | 150 | iov[0].iov_len -= rem; |
139 | } | 151 | } |
152 | if (cb != NULL && cb(cb_arg, (size_t)res) == -1) { | ||
153 | errno = EINTR; | ||
154 | return pos; | ||
155 | } | ||
140 | } | 156 | } |
141 | return pos; | 157 | return pos; |
142 | } | 158 | } |
159 | |||
160 | size_t | ||
161 | atomiciov(ssize_t (*f) (int, const struct iovec *, int), int fd, | ||
162 | const struct iovec *_iov, int iovcnt) | ||
163 | { | ||
164 | return atomiciov6(f, fd, _iov, iovcnt, NULL, NULL); | ||
165 | } | ||
diff --git a/atomicio.h b/atomicio.h index 2fcd25d43..0d728ac86 100644 --- a/atomicio.h +++ b/atomicio.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: atomicio.h,v 1.10 2006/08/03 03:34:41 deraadt Exp $ */ | 1 | /* $OpenBSD: atomicio.h,v 1.11 2010/09/22 22:58:51 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2006 Damien Miller. All rights reserved. | 4 | * Copyright (c) 2006 Damien Miller. All rights reserved. |
@@ -32,6 +32,9 @@ | |||
32 | /* | 32 | /* |
33 | * Ensure all of data on socket comes through. f==read || f==vwrite | 33 | * Ensure all of data on socket comes through. f==read || f==vwrite |
34 | */ | 34 | */ |
35 | size_t | ||
36 | atomicio6(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n, | ||
37 | int (*cb)(void *, size_t), void *); | ||
35 | size_t atomicio(ssize_t (*)(int, void *, size_t), int, void *, size_t); | 38 | size_t atomicio(ssize_t (*)(int, void *, size_t), int, void *, size_t); |
36 | 39 | ||
37 | #define vwrite (ssize_t (*)(int, void *, size_t))write | 40 | #define vwrite (ssize_t (*)(int, void *, size_t))write |
@@ -39,6 +42,9 @@ size_t atomicio(ssize_t (*)(int, void *, size_t), int, void *, size_t); | |||
39 | /* | 42 | /* |
40 | * ensure all of data on socket comes through. f==readv || f==writev | 43 | * ensure all of data on socket comes through. f==readv || f==writev |
41 | */ | 44 | */ |
45 | size_t | ||
46 | atomiciov6(ssize_t (*f) (int, const struct iovec *, int), int fd, | ||
47 | const struct iovec *_iov, int iovcnt, int (*cb)(void *, size_t), void *); | ||
42 | size_t atomiciov(ssize_t (*)(int, const struct iovec *, int), | 48 | size_t atomiciov(ssize_t (*)(int, const struct iovec *, int), |
43 | int, const struct iovec *, int); | 49 | int, const struct iovec *, int); |
44 | 50 | ||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: misc.c,v 1.80 2010/07/21 02:10:58 djm Exp $ */ | 1 | /* $OpenBSD: misc.c,v 1.81 2010/09/22 22:58:51 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. |
4 | * Copyright (c) 2005,2006 Damien Miller. All rights reserved. | 4 | * Copyright (c) 2005,2006 Damien Miller. All rights reserved. |
@@ -860,6 +860,70 @@ timingsafe_bcmp(const void *b1, const void *b2, size_t n) | |||
860 | ret |= *p1++ ^ *p2++; | 860 | ret |= *p1++ ^ *p2++; |
861 | return (ret != 0); | 861 | return (ret != 0); |
862 | } | 862 | } |
863 | |||
864 | void | ||
865 | bandwidth_limit_init(struct bwlimit *bw, u_int64_t kbps, size_t buflen) | ||
866 | { | ||
867 | bw->buflen = buflen; | ||
868 | bw->rate = kbps; | ||
869 | bw->thresh = bw->rate; | ||
870 | bw->lamt = 0; | ||
871 | timerclear(&bw->bwstart); | ||
872 | timerclear(&bw->bwend); | ||
873 | } | ||
874 | |||
875 | /* Callback from read/write loop to insert bandwidth-limiting delays */ | ||
876 | void | ||
877 | bandwidth_limit(struct bwlimit *bw, size_t read_len) | ||
878 | { | ||
879 | u_int64_t waitlen; | ||
880 | struct timespec ts, rm; | ||
881 | |||
882 | if (!timerisset(&bw->bwstart)) { | ||
883 | gettimeofday(&bw->bwstart, NULL); | ||
884 | return; | ||
885 | } | ||
886 | |||
887 | bw->lamt += read_len; | ||
888 | if (bw->lamt < bw->thresh) | ||
889 | return; | ||
890 | |||
891 | gettimeofday(&bw->bwend, NULL); | ||
892 | timersub(&bw->bwend, &bw->bwstart, &bw->bwend); | ||
893 | if (!timerisset(&bw->bwend)) | ||
894 | return; | ||
895 | |||
896 | bw->lamt *= 8; | ||
897 | waitlen = (double)1000000L * bw->lamt / bw->rate; | ||
898 | |||
899 | bw->bwstart.tv_sec = waitlen / 1000000L; | ||
900 | bw->bwstart.tv_usec = waitlen % 1000000L; | ||
901 | |||
902 | if (timercmp(&bw->bwstart, &bw->bwend, >)) { | ||
903 | timersub(&bw->bwstart, &bw->bwend, &bw->bwend); | ||
904 | |||
905 | /* Adjust the wait time */ | ||
906 | if (bw->bwend.tv_sec) { | ||
907 | bw->thresh /= 2; | ||
908 | if (bw->thresh < bw->buflen / 4) | ||
909 | bw->thresh = bw->buflen / 4; | ||
910 | } else if (bw->bwend.tv_usec < 10000) { | ||
911 | bw->thresh *= 2; | ||
912 | if (bw->thresh > bw->buflen * 8) | ||
913 | bw->thresh = bw->buflen * 8; | ||
914 | } | ||
915 | |||
916 | TIMEVAL_TO_TIMESPEC(&bw->bwend, &ts); | ||
917 | while (nanosleep(&ts, &rm) == -1) { | ||
918 | if (errno != EINTR) | ||
919 | break; | ||
920 | ts = rm; | ||
921 | } | ||
922 | } | ||
923 | |||
924 | bw->lamt = 0; | ||
925 | gettimeofday(&bw->bwstart, NULL); | ||
926 | } | ||
863 | void | 927 | void |
864 | sock_set_v6only(int s) | 928 | sock_set_v6only(int s) |
865 | { | 929 | { |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: misc.h,v 1.43 2010/07/13 23:13:16 djm Exp $ */ | 1 | /* $OpenBSD: misc.h,v 1.44 2010/09/22 22:58:51 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
@@ -80,6 +80,15 @@ void put_u32(void *, u_int32_t) | |||
80 | void put_u16(void *, u_int16_t) | 80 | void put_u16(void *, u_int16_t) |
81 | __attribute__((__bounded__( __minbytes__, 1, 2))); | 81 | __attribute__((__bounded__( __minbytes__, 1, 2))); |
82 | 82 | ||
83 | struct bwlimit { | ||
84 | size_t buflen; | ||
85 | u_int64_t rate, thresh, lamt; | ||
86 | struct timeval bwstart, bwend; | ||
87 | }; | ||
88 | |||
89 | void bandwidth_limit_init(struct bwlimit *, u_int64_t, size_t); | ||
90 | void bandwidth_limit(struct bwlimit *, size_t); | ||
91 | |||
83 | 92 | ||
84 | /* readpass.c */ | 93 | /* readpass.c */ |
85 | 94 | ||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: scp.c,v 1.166 2010/07/01 13:06:59 millert Exp $ */ | 1 | /* $OpenBSD: scp.c,v 1.167 2010/09/22 22:58:51 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * scp - secure remote copy. This is basically patched BSD rcp which | 3 | * scp - secure remote copy. This is basically patched BSD rcp which |
4 | * uses ssh to do the data transfer (instead of using rcmd). | 4 | * uses ssh to do the data transfer (instead of using rcmd). |
@@ -120,13 +120,12 @@ extern char *__progname; | |||
120 | 120 | ||
121 | int do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout); | 121 | int do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout); |
122 | 122 | ||
123 | void bwlimit(int); | ||
124 | |||
125 | /* Struct for addargs */ | 123 | /* Struct for addargs */ |
126 | arglist args; | 124 | arglist args; |
127 | 125 | ||
128 | /* Bandwidth limit */ | 126 | /* Bandwidth limit */ |
129 | off_t limit_rate = 0; | 127 | long long limit_kbps = 0; |
128 | struct bwlimit bwlimit; | ||
130 | 129 | ||
131 | /* Name of current file being transferred. */ | 130 | /* Name of current file being transferred. */ |
132 | char *curfile; | 131 | char *curfile; |
@@ -312,15 +311,14 @@ void sink(int, char *[]); | |||
312 | void source(int, char *[]); | 311 | void source(int, char *[]); |
313 | void tolocal(int, char *[]); | 312 | void tolocal(int, char *[]); |
314 | void toremote(char *, int, char *[]); | 313 | void toremote(char *, int, char *[]); |
315 | size_t scpio(ssize_t (*)(int, void *, size_t), int, void *, size_t, off_t *); | ||
316 | void usage(void); | 314 | void usage(void); |
317 | 315 | ||
318 | int | 316 | int |
319 | main(int argc, char **argv) | 317 | main(int argc, char **argv) |
320 | { | 318 | { |
321 | int ch, fflag, tflag, status, n; | 319 | int ch, fflag, tflag, status, n; |
322 | double speed; | 320 | char *targ, **newargv; |
323 | char *targ, *endp, **newargv; | 321 | const char *errstr; |
324 | extern char *optarg; | 322 | extern char *optarg; |
325 | extern int optind; | 323 | extern int optind; |
326 | 324 | ||
@@ -369,10 +367,12 @@ main(int argc, char **argv) | |||
369 | addargs(&args, "-oBatchmode yes"); | 367 | addargs(&args, "-oBatchmode yes"); |
370 | break; | 368 | break; |
371 | case 'l': | 369 | case 'l': |
372 | speed = strtod(optarg, &endp); | 370 | limit_kbps = strtonum(optarg, 1, 100 * 1024 * 1024, |
373 | if (speed <= 0 || *endp != '\0') | 371 | &errstr); |
372 | if (errstr != NULL) | ||
374 | usage(); | 373 | usage(); |
375 | limit_rate = speed * 1024; | 374 | limit_kbps *= 1024; /* kbps */ |
375 | bandwidth_limit_init(&bwlimit, limit_kbps, COPY_BUFLEN); | ||
376 | break; | 376 | break; |
377 | case 'p': | 377 | case 'p': |
378 | pflag = 1; | 378 | pflag = 1; |
@@ -474,41 +474,16 @@ main(int argc, char **argv) | |||
474 | exit(errs != 0); | 474 | exit(errs != 0); |
475 | } | 475 | } |
476 | 476 | ||
477 | /* | 477 | /* Callback from atomicio6 to update progress meter and limit bandwidth */ |
478 | * atomicio-like wrapper that also applies bandwidth limits and updates | 478 | static int |
479 | * the progressmeter counter. | 479 | scpio(void *_cnt, size_t s) |
480 | */ | ||
481 | size_t | ||
482 | scpio(ssize_t (*f)(int, void *, size_t), int fd, void *_p, size_t l, off_t *c) | ||
483 | { | 480 | { |
484 | u_char *p = (u_char *)_p; | 481 | off_t *cnt = (off_t *)_cnt; |
485 | size_t offset; | 482 | |
486 | ssize_t r; | 483 | *cnt += s; |
487 | struct pollfd pfd; | 484 | if (limit_kbps > 0) |
488 | 485 | bandwidth_limit(&bwlimit, s); | |
489 | pfd.fd = fd; | 486 | return 0; |
490 | pfd.events = f == read ? POLLIN : POLLOUT; | ||
491 | for (offset = 0; offset < l;) { | ||
492 | r = f(fd, p + offset, l - offset); | ||
493 | if (r == 0) { | ||
494 | errno = EPIPE; | ||
495 | return offset; | ||
496 | } | ||
497 | if (r < 0) { | ||
498 | if (errno == EINTR) | ||
499 | continue; | ||
500 | if (errno == EAGAIN || errno == EWOULDBLOCK) { | ||
501 | (void)poll(&pfd, 1, -1); /* Ignore errors */ | ||
502 | continue; | ||
503 | } | ||
504 | return offset; | ||
505 | } | ||
506 | offset += (size_t)r; | ||
507 | *c += (off_t)r; | ||
508 | if (limit_rate) | ||
509 | bwlimit(r); | ||
510 | } | ||
511 | return offset; | ||
512 | } | 487 | } |
513 | 488 | ||
514 | void | 489 | void |
@@ -750,7 +725,7 @@ next: if (fd != -1) { | |||
750 | (void)atomicio(vwrite, remout, bp->buf, amt); | 725 | (void)atomicio(vwrite, remout, bp->buf, amt); |
751 | continue; | 726 | continue; |
752 | } | 727 | } |
753 | if (scpio(vwrite, remout, bp->buf, amt, | 728 | if (atomicio6(vwrite, remout, bp->buf, amt, scpio, |
754 | &statbytes) != amt) | 729 | &statbytes) != amt) |
755 | haderr = errno; | 730 | haderr = errno; |
756 | } | 731 | } |
@@ -825,60 +800,6 @@ rsource(char *name, struct stat *statp) | |||
825 | } | 800 | } |
826 | 801 | ||
827 | void | 802 | void |
828 | bwlimit(int amount) | ||
829 | { | ||
830 | static struct timeval bwstart, bwend; | ||
831 | static int lamt, thresh = 16384; | ||
832 | u_int64_t waitlen; | ||
833 | struct timespec ts, rm; | ||
834 | |||
835 | if (!timerisset(&bwstart)) { | ||
836 | gettimeofday(&bwstart, NULL); | ||
837 | return; | ||
838 | } | ||
839 | |||
840 | lamt += amount; | ||
841 | if (lamt < thresh) | ||
842 | return; | ||
843 | |||
844 | gettimeofday(&bwend, NULL); | ||
845 | timersub(&bwend, &bwstart, &bwend); | ||
846 | if (!timerisset(&bwend)) | ||
847 | return; | ||
848 | |||
849 | lamt *= 8; | ||
850 | waitlen = (double)1000000L * lamt / limit_rate; | ||
851 | |||
852 | bwstart.tv_sec = waitlen / 1000000L; | ||
853 | bwstart.tv_usec = waitlen % 1000000L; | ||
854 | |||
855 | if (timercmp(&bwstart, &bwend, >)) { | ||
856 | timersub(&bwstart, &bwend, &bwend); | ||
857 | |||
858 | /* Adjust the wait time */ | ||
859 | if (bwend.tv_sec) { | ||
860 | thresh /= 2; | ||
861 | if (thresh < 2048) | ||
862 | thresh = 2048; | ||
863 | } else if (bwend.tv_usec < 10000) { | ||
864 | thresh *= 2; | ||
865 | if (thresh > COPY_BUFLEN * 4) | ||
866 | thresh = COPY_BUFLEN * 4; | ||
867 | } | ||
868 | |||
869 | TIMEVAL_TO_TIMESPEC(&bwend, &ts); | ||
870 | while (nanosleep(&ts, &rm) == -1) { | ||
871 | if (errno != EINTR) | ||
872 | break; | ||
873 | ts = rm; | ||
874 | } | ||
875 | } | ||
876 | |||
877 | lamt = 0; | ||
878 | gettimeofday(&bwstart, NULL); | ||
879 | } | ||
880 | |||
881 | void | ||
882 | sink(int argc, char **argv) | 803 | sink(int argc, char **argv) |
883 | { | 804 | { |
884 | static BUF buffer; | 805 | static BUF buffer; |
@@ -1071,7 +992,8 @@ bad: run_err("%s: %s", np, strerror(errno)); | |||
1071 | amt = size - i; | 992 | amt = size - i; |
1072 | count += amt; | 993 | count += amt; |
1073 | do { | 994 | do { |
1074 | j = scpio(read, remin, cp, amt, &statbytes); | 995 | j = atomicio6(read, remin, cp, amt, |
996 | scpio, &statbytes); | ||
1075 | if (j == 0) { | 997 | if (j == 0) { |
1076 | run_err("%s", j != EPIPE ? | 998 | run_err("%s", j != EPIPE ? |
1077 | strerror(errno) : | 999 | strerror(errno) : |
diff --git a/sftp-client.c b/sftp-client.c index 9dab47780..4e009ef25 100644 --- a/sftp-client.c +++ b/sftp-client.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sftp-client.c,v 1.92 2010/07/19 03:16:33 djm Exp $ */ | 1 | /* $OpenBSD: sftp-client.c,v 1.93 2010/09/22 22:58:51 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> | 3 | * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> |
4 | * | 4 | * |
@@ -76,14 +76,26 @@ struct sftp_conn { | |||
76 | #define SFTP_EXT_STATVFS 0x00000002 | 76 | #define SFTP_EXT_STATVFS 0x00000002 |
77 | #define SFTP_EXT_FSTATVFS 0x00000004 | 77 | #define SFTP_EXT_FSTATVFS 0x00000004 |
78 | u_int exts; | 78 | u_int exts; |
79 | u_int64_t limit_kbps; | ||
80 | struct bwlimit bwlimit_in, bwlimit_out; | ||
79 | }; | 81 | }; |
80 | 82 | ||
81 | static char * | 83 | static char * |
82 | get_handle(int fd, u_int expected_id, u_int *len, const char *errfmt, ...) | 84 | get_handle(struct sftp_conn *conn, u_int expected_id, u_int *len, |
83 | __attribute__((format(printf, 4, 5))); | 85 | const char *errfmt, ...) __attribute__((format(printf, 4, 5))); |
86 | |||
87 | /* ARGSUSED */ | ||
88 | static int | ||
89 | sftpio(void *_bwlimit, size_t amount) | ||
90 | { | ||
91 | struct bwlimit *bwlimit = (struct bwlimit *)_bwlimit; | ||
92 | |||
93 | bandwidth_limit(bwlimit, amount); | ||
94 | return 0; | ||
95 | } | ||
84 | 96 | ||
85 | static void | 97 | static void |
86 | send_msg(int fd, Buffer *m) | 98 | send_msg(struct sftp_conn *conn, Buffer *m) |
87 | { | 99 | { |
88 | u_char mlen[4]; | 100 | u_char mlen[4]; |
89 | struct iovec iov[2]; | 101 | struct iovec iov[2]; |
@@ -98,19 +110,22 @@ send_msg(int fd, Buffer *m) | |||
98 | iov[1].iov_base = buffer_ptr(m); | 110 | iov[1].iov_base = buffer_ptr(m); |
99 | iov[1].iov_len = buffer_len(m); | 111 | iov[1].iov_len = buffer_len(m); |
100 | 112 | ||
101 | if (atomiciov(writev, fd, iov, 2) != buffer_len(m) + sizeof(mlen)) | 113 | if (atomiciov6(writev, conn->fd_out, iov, 2, |
114 | conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_out) != | ||
115 | buffer_len(m) + sizeof(mlen)) | ||
102 | fatal("Couldn't send packet: %s", strerror(errno)); | 116 | fatal("Couldn't send packet: %s", strerror(errno)); |
103 | 117 | ||
104 | buffer_clear(m); | 118 | buffer_clear(m); |
105 | } | 119 | } |
106 | 120 | ||
107 | static void | 121 | static void |
108 | get_msg(int fd, Buffer *m) | 122 | get_msg(struct sftp_conn *conn, Buffer *m) |
109 | { | 123 | { |
110 | u_int msg_len; | 124 | u_int msg_len; |
111 | 125 | ||
112 | buffer_append_space(m, 4); | 126 | buffer_append_space(m, 4); |
113 | if (atomicio(read, fd, buffer_ptr(m), 4) != 4) { | 127 | if (atomicio6(read, conn->fd_in, buffer_ptr(m), 4, |
128 | conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_in) != 4) { | ||
114 | if (errno == EPIPE) | 129 | if (errno == EPIPE) |
115 | fatal("Connection closed"); | 130 | fatal("Connection closed"); |
116 | else | 131 | else |
@@ -122,7 +137,9 @@ get_msg(int fd, Buffer *m) | |||
122 | fatal("Received message too long %u", msg_len); | 137 | fatal("Received message too long %u", msg_len); |
123 | 138 | ||
124 | buffer_append_space(m, msg_len); | 139 | buffer_append_space(m, msg_len); |
125 | if (atomicio(read, fd, buffer_ptr(m), msg_len) != msg_len) { | 140 | if (atomicio6(read, conn->fd_in, buffer_ptr(m), msg_len, |
141 | conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_in) | ||
142 | != msg_len) { | ||
126 | if (errno == EPIPE) | 143 | if (errno == EPIPE) |
127 | fatal("Connection closed"); | 144 | fatal("Connection closed"); |
128 | else | 145 | else |
@@ -131,7 +148,7 @@ get_msg(int fd, Buffer *m) | |||
131 | } | 148 | } |
132 | 149 | ||
133 | static void | 150 | static void |
134 | send_string_request(int fd, u_int id, u_int code, char *s, | 151 | send_string_request(struct sftp_conn *conn, u_int id, u_int code, char *s, |
135 | u_int len) | 152 | u_int len) |
136 | { | 153 | { |
137 | Buffer msg; | 154 | Buffer msg; |
@@ -140,14 +157,14 @@ send_string_request(int fd, u_int id, u_int code, char *s, | |||
140 | buffer_put_char(&msg, code); | 157 | buffer_put_char(&msg, code); |
141 | buffer_put_int(&msg, id); | 158 | buffer_put_int(&msg, id); |
142 | buffer_put_string(&msg, s, len); | 159 | buffer_put_string(&msg, s, len); |
143 | send_msg(fd, &msg); | 160 | send_msg(conn, &msg); |
144 | debug3("Sent message fd %d T:%u I:%u", fd, code, id); | 161 | debug3("Sent message fd %d T:%u I:%u", conn->fd_out, code, id); |
145 | buffer_free(&msg); | 162 | buffer_free(&msg); |
146 | } | 163 | } |
147 | 164 | ||
148 | static void | 165 | static void |
149 | send_string_attrs_request(int fd, u_int id, u_int code, char *s, | 166 | send_string_attrs_request(struct sftp_conn *conn, u_int id, u_int code, |
150 | u_int len, Attrib *a) | 167 | char *s, u_int len, Attrib *a) |
151 | { | 168 | { |
152 | Buffer msg; | 169 | Buffer msg; |
153 | 170 | ||
@@ -156,19 +173,19 @@ send_string_attrs_request(int fd, u_int id, u_int code, char *s, | |||
156 | buffer_put_int(&msg, id); | 173 | buffer_put_int(&msg, id); |
157 | buffer_put_string(&msg, s, len); | 174 | buffer_put_string(&msg, s, len); |
158 | encode_attrib(&msg, a); | 175 | encode_attrib(&msg, a); |
159 | send_msg(fd, &msg); | 176 | send_msg(conn, &msg); |
160 | debug3("Sent message fd %d T:%u I:%u", fd, code, id); | 177 | debug3("Sent message fd %d T:%u I:%u", conn->fd_out, code, id); |
161 | buffer_free(&msg); | 178 | buffer_free(&msg); |
162 | } | 179 | } |
163 | 180 | ||
164 | static u_int | 181 | static u_int |
165 | get_status(int fd, u_int expected_id) | 182 | get_status(struct sftp_conn *conn, u_int expected_id) |
166 | { | 183 | { |
167 | Buffer msg; | 184 | Buffer msg; |
168 | u_int type, id, status; | 185 | u_int type, id, status; |
169 | 186 | ||
170 | buffer_init(&msg); | 187 | buffer_init(&msg); |
171 | get_msg(fd, &msg); | 188 | get_msg(conn, &msg); |
172 | type = buffer_get_char(&msg); | 189 | type = buffer_get_char(&msg); |
173 | id = buffer_get_int(&msg); | 190 | id = buffer_get_int(&msg); |
174 | 191 | ||
@@ -183,11 +200,12 @@ get_status(int fd, u_int expected_id) | |||
183 | 200 | ||
184 | debug3("SSH2_FXP_STATUS %u", status); | 201 | debug3("SSH2_FXP_STATUS %u", status); |
185 | 202 | ||
186 | return(status); | 203 | return status; |
187 | } | 204 | } |
188 | 205 | ||
189 | static char * | 206 | static char * |
190 | get_handle(int fd, u_int expected_id, u_int *len, const char *errfmt, ...) | 207 | get_handle(struct sftp_conn *conn, u_int expected_id, u_int *len, |
208 | const char *errfmt, ...) | ||
191 | { | 209 | { |
192 | Buffer msg; | 210 | Buffer msg; |
193 | u_int type, id; | 211 | u_int type, id; |
@@ -201,7 +219,7 @@ get_handle(int fd, u_int expected_id, u_int *len, const char *errfmt, ...) | |||
201 | va_end(args); | 219 | va_end(args); |
202 | 220 | ||
203 | buffer_init(&msg); | 221 | buffer_init(&msg); |
204 | get_msg(fd, &msg); | 222 | get_msg(conn, &msg); |
205 | type = buffer_get_char(&msg); | 223 | type = buffer_get_char(&msg); |
206 | id = buffer_get_int(&msg); | 224 | id = buffer_get_int(&msg); |
207 | 225 | ||
@@ -225,14 +243,14 @@ get_handle(int fd, u_int expected_id, u_int *len, const char *errfmt, ...) | |||
225 | } | 243 | } |
226 | 244 | ||
227 | static Attrib * | 245 | static Attrib * |
228 | get_decode_stat(int fd, u_int expected_id, int quiet) | 246 | get_decode_stat(struct sftp_conn *conn, u_int expected_id, int quiet) |
229 | { | 247 | { |
230 | Buffer msg; | 248 | Buffer msg; |
231 | u_int type, id; | 249 | u_int type, id; |
232 | Attrib *a; | 250 | Attrib *a; |
233 | 251 | ||
234 | buffer_init(&msg); | 252 | buffer_init(&msg); |
235 | get_msg(fd, &msg); | 253 | get_msg(conn, &msg); |
236 | 254 | ||
237 | type = buffer_get_char(&msg); | 255 | type = buffer_get_char(&msg); |
238 | id = buffer_get_int(&msg); | 256 | id = buffer_get_int(&msg); |
@@ -260,14 +278,14 @@ get_decode_stat(int fd, u_int expected_id, int quiet) | |||
260 | } | 278 | } |
261 | 279 | ||
262 | static int | 280 | static int |
263 | get_decode_statvfs(int fd, struct sftp_statvfs *st, u_int expected_id, | 281 | get_decode_statvfs(struct sftp_conn *conn, struct sftp_statvfs *st, |
264 | int quiet) | 282 | u_int expected_id, int quiet) |
265 | { | 283 | { |
266 | Buffer msg; | 284 | Buffer msg; |
267 | u_int type, id, flag; | 285 | u_int type, id, flag; |
268 | 286 | ||
269 | buffer_init(&msg); | 287 | buffer_init(&msg); |
270 | get_msg(fd, &msg); | 288 | get_msg(conn, &msg); |
271 | 289 | ||
272 | type = buffer_get_char(&msg); | 290 | type = buffer_get_char(&msg); |
273 | id = buffer_get_int(&msg); | 291 | id = buffer_get_int(&msg); |
@@ -311,21 +329,29 @@ get_decode_statvfs(int fd, struct sftp_statvfs *st, u_int expected_id, | |||
311 | } | 329 | } |
312 | 330 | ||
313 | struct sftp_conn * | 331 | struct sftp_conn * |
314 | do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests) | 332 | do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests, |
333 | u_int64_t limit_kbps) | ||
315 | { | 334 | { |
316 | u_int type, exts = 0; | 335 | u_int type; |
317 | int version; | ||
318 | Buffer msg; | 336 | Buffer msg; |
319 | struct sftp_conn *ret; | 337 | struct sftp_conn *ret; |
320 | 338 | ||
339 | ret = xmalloc(sizeof(*ret)); | ||
340 | ret->fd_in = fd_in; | ||
341 | ret->fd_out = fd_out; | ||
342 | ret->transfer_buflen = transfer_buflen; | ||
343 | ret->num_requests = num_requests; | ||
344 | ret->exts = 0; | ||
345 | ret->limit_kbps = 0; | ||
346 | |||
321 | buffer_init(&msg); | 347 | buffer_init(&msg); |
322 | buffer_put_char(&msg, SSH2_FXP_INIT); | 348 | buffer_put_char(&msg, SSH2_FXP_INIT); |
323 | buffer_put_int(&msg, SSH2_FILEXFER_VERSION); | 349 | buffer_put_int(&msg, SSH2_FILEXFER_VERSION); |
324 | send_msg(fd_out, &msg); | 350 | send_msg(ret, &msg); |
325 | 351 | ||
326 | buffer_clear(&msg); | 352 | buffer_clear(&msg); |
327 | 353 | ||
328 | get_msg(fd_in, &msg); | 354 | get_msg(ret, &msg); |
329 | 355 | ||
330 | /* Expecting a VERSION reply */ | 356 | /* Expecting a VERSION reply */ |
331 | if ((type = buffer_get_char(&msg)) != SSH2_FXP_VERSION) { | 357 | if ((type = buffer_get_char(&msg)) != SSH2_FXP_VERSION) { |
@@ -334,9 +360,9 @@ do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests) | |||
334 | buffer_free(&msg); | 360 | buffer_free(&msg); |
335 | return(NULL); | 361 | return(NULL); |
336 | } | 362 | } |
337 | version = buffer_get_int(&msg); | 363 | ret->version = buffer_get_int(&msg); |
338 | 364 | ||
339 | debug2("Remote version: %d", version); | 365 | debug2("Remote version: %u", ret->version); |
340 | 366 | ||
341 | /* Check for extensions */ | 367 | /* Check for extensions */ |
342 | while (buffer_len(&msg) > 0) { | 368 | while (buffer_len(&msg) > 0) { |
@@ -346,15 +372,15 @@ do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests) | |||
346 | 372 | ||
347 | if (strcmp(name, "posix-rename@openssh.com") == 0 && | 373 | if (strcmp(name, "posix-rename@openssh.com") == 0 && |
348 | strcmp(value, "1") == 0) { | 374 | strcmp(value, "1") == 0) { |
349 | exts |= SFTP_EXT_POSIX_RENAME; | 375 | ret->exts |= SFTP_EXT_POSIX_RENAME; |
350 | known = 1; | 376 | known = 1; |
351 | } else if (strcmp(name, "statvfs@openssh.com") == 0 && | 377 | } else if (strcmp(name, "statvfs@openssh.com") == 0 && |
352 | strcmp(value, "2") == 0) { | 378 | strcmp(value, "2") == 0) { |
353 | exts |= SFTP_EXT_STATVFS; | 379 | ret->exts |= SFTP_EXT_STATVFS; |
354 | known = 1; | 380 | known = 1; |
355 | } if (strcmp(name, "fstatvfs@openssh.com") == 0 && | 381 | } if (strcmp(name, "fstatvfs@openssh.com") == 0 && |
356 | strcmp(value, "2") == 0) { | 382 | strcmp(value, "2") == 0) { |
357 | exts |= SFTP_EXT_FSTATVFS; | 383 | ret->exts |= SFTP_EXT_FSTATVFS; |
358 | known = 1; | 384 | known = 1; |
359 | } | 385 | } |
360 | if (known) { | 386 | if (known) { |
@@ -369,26 +395,25 @@ do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests) | |||
369 | 395 | ||
370 | buffer_free(&msg); | 396 | buffer_free(&msg); |
371 | 397 | ||
372 | ret = xmalloc(sizeof(*ret)); | ||
373 | ret->fd_in = fd_in; | ||
374 | ret->fd_out = fd_out; | ||
375 | ret->transfer_buflen = transfer_buflen; | ||
376 | ret->num_requests = num_requests; | ||
377 | ret->version = version; | ||
378 | ret->msg_id = 1; | ||
379 | ret->exts = exts; | ||
380 | |||
381 | /* Some filexfer v.0 servers don't support large packets */ | 398 | /* Some filexfer v.0 servers don't support large packets */ |
382 | if (version == 0) | 399 | if (ret->version == 0) |
383 | ret->transfer_buflen = MIN(ret->transfer_buflen, 20480); | 400 | ret->transfer_buflen = MIN(ret->transfer_buflen, 20480); |
384 | 401 | ||
385 | return(ret); | 402 | ret->limit_kbps = limit_kbps; |
403 | if (ret->limit_kbps > 0) { | ||
404 | bandwidth_limit_init(&ret->bwlimit_in, ret->limit_kbps, | ||
405 | ret->transfer_buflen); | ||
406 | bandwidth_limit_init(&ret->bwlimit_out, ret->limit_kbps, | ||
407 | ret->transfer_buflen); | ||
408 | } | ||
409 | |||
410 | return ret; | ||
386 | } | 411 | } |
387 | 412 | ||
388 | u_int | 413 | u_int |
389 | sftp_proto_version(struct sftp_conn *conn) | 414 | sftp_proto_version(struct sftp_conn *conn) |
390 | { | 415 | { |
391 | return(conn->version); | 416 | return conn->version; |
392 | } | 417 | } |
393 | 418 | ||
394 | int | 419 | int |
@@ -403,16 +428,16 @@ do_close(struct sftp_conn *conn, char *handle, u_int handle_len) | |||
403 | buffer_put_char(&msg, SSH2_FXP_CLOSE); | 428 | buffer_put_char(&msg, SSH2_FXP_CLOSE); |
404 | buffer_put_int(&msg, id); | 429 | buffer_put_int(&msg, id); |
405 | buffer_put_string(&msg, handle, handle_len); | 430 | buffer_put_string(&msg, handle, handle_len); |
406 | send_msg(conn->fd_out, &msg); | 431 | send_msg(conn, &msg); |
407 | debug3("Sent message SSH2_FXP_CLOSE I:%u", id); | 432 | debug3("Sent message SSH2_FXP_CLOSE I:%u", id); |
408 | 433 | ||
409 | status = get_status(conn->fd_in, id); | 434 | status = get_status(conn, id); |
410 | if (status != SSH2_FX_OK) | 435 | if (status != SSH2_FX_OK) |
411 | error("Couldn't close file: %s", fx2txt(status)); | 436 | error("Couldn't close file: %s", fx2txt(status)); |
412 | 437 | ||
413 | buffer_free(&msg); | 438 | buffer_free(&msg); |
414 | 439 | ||
415 | return(status); | 440 | return status; |
416 | } | 441 | } |
417 | 442 | ||
418 | 443 | ||
@@ -430,14 +455,14 @@ do_lsreaddir(struct sftp_conn *conn, char *path, int printflag, | |||
430 | buffer_put_char(&msg, SSH2_FXP_OPENDIR); | 455 | buffer_put_char(&msg, SSH2_FXP_OPENDIR); |
431 | buffer_put_int(&msg, id); | 456 | buffer_put_int(&msg, id); |
432 | buffer_put_cstring(&msg, path); | 457 | buffer_put_cstring(&msg, path); |
433 | send_msg(conn->fd_out, &msg); | 458 | send_msg(conn, &msg); |
434 | 459 | ||
435 | buffer_clear(&msg); | 460 | buffer_clear(&msg); |
436 | 461 | ||
437 | handle = get_handle(conn->fd_in, id, &handle_len, | 462 | handle = get_handle(conn, id, &handle_len, |
438 | "remote readdir(\"%s\")", path); | 463 | "remote readdir(\"%s\")", path); |
439 | if (handle == NULL) | 464 | if (handle == NULL) |
440 | return(-1); | 465 | return -1; |
441 | 466 | ||
442 | if (dir) { | 467 | if (dir) { |
443 | ents = 0; | 468 | ents = 0; |
@@ -454,11 +479,11 @@ do_lsreaddir(struct sftp_conn *conn, char *path, int printflag, | |||
454 | buffer_put_char(&msg, SSH2_FXP_READDIR); | 479 | buffer_put_char(&msg, SSH2_FXP_READDIR); |
455 | buffer_put_int(&msg, id); | 480 | buffer_put_int(&msg, id); |
456 | buffer_put_string(&msg, handle, handle_len); | 481 | buffer_put_string(&msg, handle, handle_len); |
457 | send_msg(conn->fd_out, &msg); | 482 | send_msg(conn, &msg); |
458 | 483 | ||
459 | buffer_clear(&msg); | 484 | buffer_clear(&msg); |
460 | 485 | ||
461 | get_msg(conn->fd_in, &msg); | 486 | get_msg(conn, &msg); |
462 | 487 | ||
463 | type = buffer_get_char(&msg); | 488 | type = buffer_get_char(&msg); |
464 | id = buffer_get_int(&msg); | 489 | id = buffer_get_int(&msg); |
@@ -537,7 +562,7 @@ do_lsreaddir(struct sftp_conn *conn, char *path, int printflag, | |||
537 | **dir = NULL; | 562 | **dir = NULL; |
538 | } | 563 | } |
539 | 564 | ||
540 | return(0); | 565 | return 0; |
541 | } | 566 | } |
542 | 567 | ||
543 | int | 568 | int |
@@ -566,9 +591,8 @@ do_rm(struct sftp_conn *conn, char *path) | |||
566 | debug2("Sending SSH2_FXP_REMOVE \"%s\"", path); | 591 | debug2("Sending SSH2_FXP_REMOVE \"%s\"", path); |
567 | 592 | ||
568 | id = conn->msg_id++; | 593 | id = conn->msg_id++; |
569 | send_string_request(conn->fd_out, id, SSH2_FXP_REMOVE, path, | 594 | send_string_request(conn, id, SSH2_FXP_REMOVE, path, strlen(path)); |
570 | strlen(path)); | 595 | status = get_status(conn, id); |
571 | status = get_status(conn->fd_in, id); | ||
572 | if (status != SSH2_FX_OK) | 596 | if (status != SSH2_FX_OK) |
573 | error("Couldn't delete file: %s", fx2txt(status)); | 597 | error("Couldn't delete file: %s", fx2txt(status)); |
574 | return(status); | 598 | return(status); |
@@ -580,10 +604,10 @@ do_mkdir(struct sftp_conn *conn, char *path, Attrib *a, int printflag) | |||
580 | u_int status, id; | 604 | u_int status, id; |
581 | 605 | ||
582 | id = conn->msg_id++; | 606 | id = conn->msg_id++; |
583 | send_string_attrs_request(conn->fd_out, id, SSH2_FXP_MKDIR, path, | 607 | send_string_attrs_request(conn, id, SSH2_FXP_MKDIR, path, |
584 | strlen(path), a); | 608 | strlen(path), a); |
585 | 609 | ||
586 | status = get_status(conn->fd_in, id); | 610 | status = get_status(conn, id); |
587 | if (status != SSH2_FX_OK && printflag) | 611 | if (status != SSH2_FX_OK && printflag) |
588 | error("Couldn't create directory: %s", fx2txt(status)); | 612 | error("Couldn't create directory: %s", fx2txt(status)); |
589 | 613 | ||
@@ -596,10 +620,10 @@ do_rmdir(struct sftp_conn *conn, char *path) | |||
596 | u_int status, id; | 620 | u_int status, id; |
597 | 621 | ||
598 | id = conn->msg_id++; | 622 | id = conn->msg_id++; |
599 | send_string_request(conn->fd_out, id, SSH2_FXP_RMDIR, path, | 623 | send_string_request(conn, id, SSH2_FXP_RMDIR, path, |
600 | strlen(path)); | 624 | strlen(path)); |
601 | 625 | ||
602 | status = get_status(conn->fd_in, id); | 626 | status = get_status(conn, id); |
603 | if (status != SSH2_FX_OK) | 627 | if (status != SSH2_FX_OK) |
604 | error("Couldn't remove directory: %s", fx2txt(status)); | 628 | error("Couldn't remove directory: %s", fx2txt(status)); |
605 | 629 | ||
@@ -613,11 +637,11 @@ do_stat(struct sftp_conn *conn, char *path, int quiet) | |||
613 | 637 | ||
614 | id = conn->msg_id++; | 638 | id = conn->msg_id++; |
615 | 639 | ||
616 | send_string_request(conn->fd_out, id, | 640 | send_string_request(conn, id, |
617 | conn->version == 0 ? SSH2_FXP_STAT_VERSION_0 : SSH2_FXP_STAT, | 641 | conn->version == 0 ? SSH2_FXP_STAT_VERSION_0 : SSH2_FXP_STAT, |
618 | path, strlen(path)); | 642 | path, strlen(path)); |
619 | 643 | ||
620 | return(get_decode_stat(conn->fd_in, id, quiet)); | 644 | return(get_decode_stat(conn, id, quiet)); |
621 | } | 645 | } |
622 | 646 | ||
623 | Attrib * | 647 | Attrib * |
@@ -634,10 +658,10 @@ do_lstat(struct sftp_conn *conn, char *path, int quiet) | |||
634 | } | 658 | } |
635 | 659 | ||
636 | id = conn->msg_id++; | 660 | id = conn->msg_id++; |
637 | send_string_request(conn->fd_out, id, SSH2_FXP_LSTAT, path, | 661 | send_string_request(conn, id, SSH2_FXP_LSTAT, path, |
638 | strlen(path)); | 662 | strlen(path)); |
639 | 663 | ||
640 | return(get_decode_stat(conn->fd_in, id, quiet)); | 664 | return(get_decode_stat(conn, id, quiet)); |
641 | } | 665 | } |
642 | 666 | ||
643 | #ifdef notyet | 667 | #ifdef notyet |
@@ -647,10 +671,10 @@ do_fstat(struct sftp_conn *conn, char *handle, u_int handle_len, int quiet) | |||
647 | u_int id; | 671 | u_int id; |
648 | 672 | ||
649 | id = conn->msg_id++; | 673 | id = conn->msg_id++; |
650 | send_string_request(conn->fd_out, id, SSH2_FXP_FSTAT, handle, | 674 | send_string_request(conn, id, SSH2_FXP_FSTAT, handle, |
651 | handle_len); | 675 | handle_len); |
652 | 676 | ||
653 | return(get_decode_stat(conn->fd_in, id, quiet)); | 677 | return(get_decode_stat(conn, id, quiet)); |
654 | } | 678 | } |
655 | #endif | 679 | #endif |
656 | 680 | ||
@@ -660,10 +684,10 @@ do_setstat(struct sftp_conn *conn, char *path, Attrib *a) | |||
660 | u_int status, id; | 684 | u_int status, id; |
661 | 685 | ||
662 | id = conn->msg_id++; | 686 | id = conn->msg_id++; |
663 | send_string_attrs_request(conn->fd_out, id, SSH2_FXP_SETSTAT, path, | 687 | send_string_attrs_request(conn, id, SSH2_FXP_SETSTAT, path, |
664 | strlen(path), a); | 688 | strlen(path), a); |
665 | 689 | ||
666 | status = get_status(conn->fd_in, id); | 690 | status = get_status(conn, id); |
667 | if (status != SSH2_FX_OK) | 691 | if (status != SSH2_FX_OK) |
668 | error("Couldn't setstat on \"%s\": %s", path, | 692 | error("Couldn't setstat on \"%s\": %s", path, |
669 | fx2txt(status)); | 693 | fx2txt(status)); |
@@ -678,10 +702,10 @@ do_fsetstat(struct sftp_conn *conn, char *handle, u_int handle_len, | |||
678 | u_int status, id; | 702 | u_int status, id; |
679 | 703 | ||
680 | id = conn->msg_id++; | 704 | id = conn->msg_id++; |
681 | send_string_attrs_request(conn->fd_out, id, SSH2_FXP_FSETSTAT, handle, | 705 | send_string_attrs_request(conn, id, SSH2_FXP_FSETSTAT, handle, |
682 | handle_len, a); | 706 | handle_len, a); |
683 | 707 | ||
684 | status = get_status(conn->fd_in, id); | 708 | status = get_status(conn, id); |
685 | if (status != SSH2_FX_OK) | 709 | if (status != SSH2_FX_OK) |
686 | error("Couldn't fsetstat: %s", fx2txt(status)); | 710 | error("Couldn't fsetstat: %s", fx2txt(status)); |
687 | 711 | ||
@@ -697,12 +721,12 @@ do_realpath(struct sftp_conn *conn, char *path) | |||
697 | Attrib *a; | 721 | Attrib *a; |
698 | 722 | ||
699 | expected_id = id = conn->msg_id++; | 723 | expected_id = id = conn->msg_id++; |
700 | send_string_request(conn->fd_out, id, SSH2_FXP_REALPATH, path, | 724 | send_string_request(conn, id, SSH2_FXP_REALPATH, path, |
701 | strlen(path)); | 725 | strlen(path)); |
702 | 726 | ||
703 | buffer_init(&msg); | 727 | buffer_init(&msg); |
704 | 728 | ||
705 | get_msg(conn->fd_in, &msg); | 729 | get_msg(conn, &msg); |
706 | type = buffer_get_char(&msg); | 730 | type = buffer_get_char(&msg); |
707 | id = buffer_get_int(&msg); | 731 | id = buffer_get_int(&msg); |
708 | 732 | ||
@@ -756,13 +780,13 @@ do_rename(struct sftp_conn *conn, char *oldpath, char *newpath) | |||
756 | } | 780 | } |
757 | buffer_put_cstring(&msg, oldpath); | 781 | buffer_put_cstring(&msg, oldpath); |
758 | buffer_put_cstring(&msg, newpath); | 782 | buffer_put_cstring(&msg, newpath); |
759 | send_msg(conn->fd_out, &msg); | 783 | send_msg(conn, &msg); |
760 | debug3("Sent message %s \"%s\" -> \"%s\"", | 784 | debug3("Sent message %s \"%s\" -> \"%s\"", |
761 | (conn->exts & SFTP_EXT_POSIX_RENAME) ? "posix-rename@openssh.com" : | 785 | (conn->exts & SFTP_EXT_POSIX_RENAME) ? "posix-rename@openssh.com" : |
762 | "SSH2_FXP_RENAME", oldpath, newpath); | 786 | "SSH2_FXP_RENAME", oldpath, newpath); |
763 | buffer_free(&msg); | 787 | buffer_free(&msg); |
764 | 788 | ||
765 | status = get_status(conn->fd_in, id); | 789 | status = get_status(conn, id); |
766 | if (status != SSH2_FX_OK) | 790 | if (status != SSH2_FX_OK) |
767 | error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, | 791 | error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, |
768 | newpath, fx2txt(status)); | 792 | newpath, fx2txt(status)); |
@@ -789,12 +813,12 @@ do_symlink(struct sftp_conn *conn, char *oldpath, char *newpath) | |||
789 | buffer_put_int(&msg, id); | 813 | buffer_put_int(&msg, id); |
790 | buffer_put_cstring(&msg, oldpath); | 814 | buffer_put_cstring(&msg, oldpath); |
791 | buffer_put_cstring(&msg, newpath); | 815 | buffer_put_cstring(&msg, newpath); |
792 | send_msg(conn->fd_out, &msg); | 816 | send_msg(conn, &msg); |
793 | debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath, | 817 | debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath, |
794 | newpath); | 818 | newpath); |
795 | buffer_free(&msg); | 819 | buffer_free(&msg); |
796 | 820 | ||
797 | status = get_status(conn->fd_in, id); | 821 | status = get_status(conn, id); |
798 | if (status != SSH2_FX_OK) | 822 | if (status != SSH2_FX_OK) |
799 | error("Couldn't symlink file \"%s\" to \"%s\": %s", oldpath, | 823 | error("Couldn't symlink file \"%s\" to \"%s\": %s", oldpath, |
800 | newpath, fx2txt(status)); | 824 | newpath, fx2txt(status)); |
@@ -812,12 +836,11 @@ do_readlink(struct sftp_conn *conn, char *path) | |||
812 | Attrib *a; | 836 | Attrib *a; |
813 | 837 | ||
814 | expected_id = id = conn->msg_id++; | 838 | expected_id = id = conn->msg_id++; |
815 | send_string_request(conn->fd_out, id, SSH2_FXP_READLINK, path, | 839 | send_string_request(conn, id, SSH2_FXP_READLINK, path, strlen(path)); |
816 | strlen(path)); | ||
817 | 840 | ||
818 | buffer_init(&msg); | 841 | buffer_init(&msg); |
819 | 842 | ||
820 | get_msg(conn->fd_in, &msg); | 843 | get_msg(conn, &msg); |
821 | type = buffer_get_char(&msg); | 844 | type = buffer_get_char(&msg); |
822 | id = buffer_get_int(&msg); | 845 | id = buffer_get_int(&msg); |
823 | 846 | ||
@@ -871,10 +894,10 @@ do_statvfs(struct sftp_conn *conn, const char *path, struct sftp_statvfs *st, | |||
871 | buffer_put_int(&msg, id); | 894 | buffer_put_int(&msg, id); |
872 | buffer_put_cstring(&msg, "statvfs@openssh.com"); | 895 | buffer_put_cstring(&msg, "statvfs@openssh.com"); |
873 | buffer_put_cstring(&msg, path); | 896 | buffer_put_cstring(&msg, path); |
874 | send_msg(conn->fd_out, &msg); | 897 | send_msg(conn, &msg); |
875 | buffer_free(&msg); | 898 | buffer_free(&msg); |
876 | 899 | ||
877 | return get_decode_statvfs(conn->fd_in, st, id, quiet); | 900 | return get_decode_statvfs(conn, st, id, quiet); |
878 | } | 901 | } |
879 | 902 | ||
880 | #ifdef notyet | 903 | #ifdef notyet |
@@ -898,16 +921,16 @@ do_fstatvfs(struct sftp_conn *conn, const char *handle, u_int handle_len, | |||
898 | buffer_put_int(&msg, id); | 921 | buffer_put_int(&msg, id); |
899 | buffer_put_cstring(&msg, "fstatvfs@openssh.com"); | 922 | buffer_put_cstring(&msg, "fstatvfs@openssh.com"); |
900 | buffer_put_string(&msg, handle, handle_len); | 923 | buffer_put_string(&msg, handle, handle_len); |
901 | send_msg(conn->fd_out, &msg); | 924 | send_msg(conn, &msg); |
902 | buffer_free(&msg); | 925 | buffer_free(&msg); |
903 | 926 | ||
904 | return get_decode_statvfs(conn->fd_in, st, id, quiet); | 927 | return get_decode_statvfs(conn, st, id, quiet); |
905 | } | 928 | } |
906 | #endif | 929 | #endif |
907 | 930 | ||
908 | static void | 931 | static void |
909 | send_read_request(int fd_out, u_int id, u_int64_t offset, u_int len, | 932 | send_read_request(struct sftp_conn *conn, u_int id, u_int64_t offset, |
910 | char *handle, u_int handle_len) | 933 | u_int len, char *handle, u_int handle_len) |
911 | { | 934 | { |
912 | Buffer msg; | 935 | Buffer msg; |
913 | 936 | ||
@@ -918,7 +941,7 @@ send_read_request(int fd_out, u_int id, u_int64_t offset, u_int len, | |||
918 | buffer_put_string(&msg, handle, handle_len); | 941 | buffer_put_string(&msg, handle, handle_len); |
919 | buffer_put_int64(&msg, offset); | 942 | buffer_put_int64(&msg, offset); |
920 | buffer_put_int(&msg, len); | 943 | buffer_put_int(&msg, len); |
921 | send_msg(fd_out, &msg); | 944 | send_msg(conn, &msg); |
922 | buffer_free(&msg); | 945 | buffer_free(&msg); |
923 | } | 946 | } |
924 | 947 | ||
@@ -976,10 +999,10 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, | |||
976 | buffer_put_int(&msg, SSH2_FXF_READ); | 999 | buffer_put_int(&msg, SSH2_FXF_READ); |
977 | attrib_clear(&junk); /* Send empty attributes */ | 1000 | attrib_clear(&junk); /* Send empty attributes */ |
978 | encode_attrib(&msg, &junk); | 1001 | encode_attrib(&msg, &junk); |
979 | send_msg(conn->fd_out, &msg); | 1002 | send_msg(conn, &msg); |
980 | debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path); | 1003 | debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path); |
981 | 1004 | ||
982 | handle = get_handle(conn->fd_in, id, &handle_len, | 1005 | handle = get_handle(conn, id, &handle_len, |
983 | "remote open(\"%s\")", remote_path); | 1006 | "remote open(\"%s\")", remote_path); |
984 | if (handle == NULL) { | 1007 | if (handle == NULL) { |
985 | buffer_free(&msg); | 1008 | buffer_free(&msg); |
@@ -1032,12 +1055,12 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, | |||
1032 | offset += buflen; | 1055 | offset += buflen; |
1033 | num_req++; | 1056 | num_req++; |
1034 | TAILQ_INSERT_TAIL(&requests, req, tq); | 1057 | TAILQ_INSERT_TAIL(&requests, req, tq); |
1035 | send_read_request(conn->fd_out, req->id, req->offset, | 1058 | send_read_request(conn, req->id, req->offset, |
1036 | req->len, handle, handle_len); | 1059 | req->len, handle, handle_len); |
1037 | } | 1060 | } |
1038 | 1061 | ||
1039 | buffer_clear(&msg); | 1062 | buffer_clear(&msg); |
1040 | get_msg(conn->fd_in, &msg); | 1063 | get_msg(conn, &msg); |
1041 | type = buffer_get_char(&msg); | 1064 | type = buffer_get_char(&msg); |
1042 | id = buffer_get_int(&msg); | 1065 | id = buffer_get_int(&msg); |
1043 | debug3("Received reply T:%u I:%u R:%d", type, id, max_req); | 1066 | debug3("Received reply T:%u I:%u R:%d", type, id, max_req); |
@@ -1092,7 +1115,7 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, | |||
1092 | req->id = conn->msg_id++; | 1115 | req->id = conn->msg_id++; |
1093 | req->len -= len; | 1116 | req->len -= len; |
1094 | req->offset += len; | 1117 | req->offset += len; |
1095 | send_read_request(conn->fd_out, req->id, | 1118 | send_read_request(conn, req->id, |
1096 | req->offset, req->len, handle, handle_len); | 1119 | req->offset, req->len, handle, handle_len); |
1097 | /* Reduce the request size */ | 1120 | /* Reduce the request size */ |
1098 | if (len < buflen) | 1121 | if (len < buflen) |
@@ -1327,12 +1350,12 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, | |||
1327 | buffer_put_cstring(&msg, remote_path); | 1350 | buffer_put_cstring(&msg, remote_path); |
1328 | buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC); | 1351 | buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC); |
1329 | encode_attrib(&msg, &a); | 1352 | encode_attrib(&msg, &a); |
1330 | send_msg(conn->fd_out, &msg); | 1353 | send_msg(conn, &msg); |
1331 | debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path); | 1354 | debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path); |
1332 | 1355 | ||
1333 | buffer_clear(&msg); | 1356 | buffer_clear(&msg); |
1334 | 1357 | ||
1335 | handle = get_handle(conn->fd_in, id, &handle_len, | 1358 | handle = get_handle(conn, id, &handle_len, |
1336 | "remote open(\"%s\")", remote_path); | 1359 | "remote open(\"%s\")", remote_path); |
1337 | if (handle == NULL) { | 1360 | if (handle == NULL) { |
1338 | close(local_fd); | 1361 | close(local_fd); |
@@ -1381,7 +1404,7 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, | |||
1381 | buffer_put_string(&msg, handle, handle_len); | 1404 | buffer_put_string(&msg, handle, handle_len); |
1382 | buffer_put_int64(&msg, offset); | 1405 | buffer_put_int64(&msg, offset); |
1383 | buffer_put_string(&msg, data, len); | 1406 | buffer_put_string(&msg, data, len); |
1384 | send_msg(conn->fd_out, &msg); | 1407 | send_msg(conn, &msg); |
1385 | debug3("Sent message SSH2_FXP_WRITE I:%u O:%llu S:%u", | 1408 | debug3("Sent message SSH2_FXP_WRITE I:%u O:%llu S:%u", |
1386 | id, (unsigned long long)offset, len); | 1409 | id, (unsigned long long)offset, len); |
1387 | } else if (TAILQ_FIRST(&acks) == NULL) | 1410 | } else if (TAILQ_FIRST(&acks) == NULL) |
@@ -1395,7 +1418,7 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, | |||
1395 | u_int r_id; | 1418 | u_int r_id; |
1396 | 1419 | ||
1397 | buffer_clear(&msg); | 1420 | buffer_clear(&msg); |
1398 | get_msg(conn->fd_in, &msg); | 1421 | get_msg(conn, &msg); |
1399 | type = buffer_get_char(&msg); | 1422 | type = buffer_get_char(&msg); |
1400 | r_id = buffer_get_int(&msg); | 1423 | r_id = buffer_get_int(&msg); |
1401 | 1424 | ||
diff --git a/sftp-client.h b/sftp-client.h index 1d08c4049..145fc38ee 100644 --- a/sftp-client.h +++ b/sftp-client.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sftp-client.h,v 1.18 2009/08/18 18:36:20 djm Exp $ */ | 1 | /* $OpenBSD: sftp-client.h,v 1.19 2010/09/22 22:58:51 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> | 4 | * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> |
@@ -51,7 +51,7 @@ struct sftp_statvfs { | |||
51 | * Initialise a SSH filexfer connection. Returns NULL on error or | 51 | * Initialise a SSH filexfer connection. Returns NULL on error or |
52 | * a pointer to a initialized sftp_conn struct on success. | 52 | * a pointer to a initialized sftp_conn struct on success. |
53 | */ | 53 | */ |
54 | struct sftp_conn *do_init(int, int, u_int, u_int); | 54 | struct sftp_conn *do_init(int, int, u_int, u_int, u_int64_t); |
55 | 55 | ||
56 | u_int sftp_proto_version(struct sftp_conn *); | 56 | u_int sftp_proto_version(struct sftp_conn *); |
57 | 57 | ||
@@ -1,4 +1,4 @@ | |||
1 | .\" $OpenBSD: sftp.1,v 1.84 2010/09/19 21:30:05 jmc Exp $ | 1 | .\" $OpenBSD: sftp.1,v 1.85 2010/09/22 22:58:51 djm Exp $ |
2 | .\" | 2 | .\" |
3 | .\" Copyright (c) 2001 Damien Miller. All rights reserved. | 3 | .\" Copyright (c) 2001 Damien Miller. All rights reserved. |
4 | .\" | 4 | .\" |
@@ -22,7 +22,7 @@ | |||
22 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 22 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
23 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 23 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
24 | .\" | 24 | .\" |
25 | .Dd $Mdocdate: September 19 2010 $ | 25 | .Dd $Mdocdate: September 22 2010 $ |
26 | .Dt SFTP 1 | 26 | .Dt SFTP 1 |
27 | .Os | 27 | .Os |
28 | .Sh NAME | 28 | .Sh NAME |
@@ -38,6 +38,7 @@ | |||
38 | .Op Fl D Ar sftp_server_path | 38 | .Op Fl D Ar sftp_server_path |
39 | .Op Fl F Ar ssh_config | 39 | .Op Fl F Ar ssh_config |
40 | .Op Fl i Ar identity_file | 40 | .Op Fl i Ar identity_file |
41 | .Op Fl l Ar limit | ||
41 | .Op Fl o Ar ssh_option | 42 | .Op Fl o Ar ssh_option |
42 | .Op Fl P Ar port | 43 | .Op Fl P Ar port |
43 | .Op Fl R Ar num_requests | 44 | .Op Fl R Ar num_requests |
@@ -159,6 +160,8 @@ Selects the file from which the identity (private key) for public key | |||
159 | authentication is read. | 160 | authentication is read. |
160 | This option is directly passed to | 161 | This option is directly passed to |
161 | .Xr ssh 1 . | 162 | .Xr ssh 1 . |
163 | .It Fl l Ar limit | ||
164 | Limits the used bandwidth, specified in Kbit/s. | ||
162 | .It Fl o Ar ssh_option | 165 | .It Fl o Ar ssh_option |
163 | Can be used to pass options to | 166 | Can be used to pass options to |
164 | .Nm ssh | 167 | .Nm ssh |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sftp.c,v 1.125 2010/06/18 00:58:39 djm Exp $ */ | 1 | /* $OpenBSD: sftp.c,v 1.126 2010/09/22 22:58:51 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> | 3 | * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> |
4 | * | 4 | * |
@@ -2073,6 +2073,7 @@ main(int argc, char **argv) | |||
2073 | int debug_level = 0, sshver = 2; | 2073 | int debug_level = 0, sshver = 2; |
2074 | char *file1 = NULL, *sftp_server = NULL; | 2074 | char *file1 = NULL, *sftp_server = NULL; |
2075 | char *ssh_program = _PATH_SSH_PROGRAM, *sftp_direct = NULL; | 2075 | char *ssh_program = _PATH_SSH_PROGRAM, *sftp_direct = NULL; |
2076 | const char *errstr; | ||
2076 | LogLevel ll = SYSLOG_LEVEL_INFO; | 2077 | LogLevel ll = SYSLOG_LEVEL_INFO; |
2077 | arglist args; | 2078 | arglist args; |
2078 | extern int optind; | 2079 | extern int optind; |
@@ -2080,6 +2081,7 @@ main(int argc, char **argv) | |||
2080 | struct sftp_conn *conn; | 2081 | struct sftp_conn *conn; |
2081 | size_t copy_buffer_len = DEFAULT_COPY_BUFLEN; | 2082 | size_t copy_buffer_len = DEFAULT_COPY_BUFLEN; |
2082 | size_t num_requests = DEFAULT_NUM_REQUESTS; | 2083 | size_t num_requests = DEFAULT_NUM_REQUESTS; |
2084 | long long limit_kbps = 0; | ||
2083 | 2085 | ||
2084 | /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ | 2086 | /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ |
2085 | sanitise_stdfd(); | 2087 | sanitise_stdfd(); |
@@ -2097,7 +2099,7 @@ main(int argc, char **argv) | |||
2097 | infile = stdin; | 2099 | infile = stdin; |
2098 | 2100 | ||
2099 | while ((ch = getopt(argc, argv, | 2101 | while ((ch = getopt(argc, argv, |
2100 | "1246hpqrvCc:D:i:o:s:S:b:B:F:P:R:")) != -1) { | 2102 | "1246hpqrvCc:D:i:l:o:s:S:b:B:F:P:R:")) != -1) { |
2101 | switch (ch) { | 2103 | switch (ch) { |
2102 | /* Passed through to ssh(1) */ | 2104 | /* Passed through to ssh(1) */ |
2103 | case '4': | 2105 | case '4': |
@@ -2158,6 +2160,13 @@ main(int argc, char **argv) | |||
2158 | case 'D': | 2160 | case 'D': |
2159 | sftp_direct = optarg; | 2161 | sftp_direct = optarg; |
2160 | break; | 2162 | break; |
2163 | case 'l': | ||
2164 | limit_kbps = strtonum(optarg, 1, 100 * 1024 * 1024, | ||
2165 | &errstr); | ||
2166 | if (errstr != NULL) | ||
2167 | usage(); | ||
2168 | limit_kbps *= 1024; /* kbps */ | ||
2169 | break; | ||
2161 | case 'r': | 2170 | case 'r': |
2162 | global_rflag = 1; | 2171 | global_rflag = 1; |
2163 | break; | 2172 | break; |
@@ -2235,7 +2244,7 @@ main(int argc, char **argv) | |||
2235 | } | 2244 | } |
2236 | freeargs(&args); | 2245 | freeargs(&args); |
2237 | 2246 | ||
2238 | conn = do_init(in, out, copy_buffer_len, num_requests); | 2247 | conn = do_init(in, out, copy_buffer_len, num_requests, limit_kbps); |
2239 | if (conn == NULL) | 2248 | if (conn == NULL) |
2240 | fatal("Couldn't initialise connection to server"); | 2249 | fatal("Couldn't initialise connection to server"); |
2241 | 2250 | ||