summaryrefslogtreecommitdiff
path: root/scp.c
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2010-09-24 22:15:11 +1000
committerDamien Miller <djm@mindrot.org>2010-09-24 22:15:11 +1000
commit65e42f87fe945a2bf30d7e02358554dbaefa8a4c (patch)
tree102c10a0b5328a40c79dca19d208f0ca0c1671b5 /scp.c
parent7fe2b1fec3b364faf952828f3875b8e7eed8feb4 (diff)
- djm@cvs.openbsd.org 2010/09/22 22:58:51
[atomicio.c atomicio.h misc.c misc.h scp.c sftp-client.c] [sftp-client.h sftp.1 sftp.c] add an option per-read/write callback to atomicio factor out bandwidth limiting code from scp(1) into a generic bandwidth limiter that can be attached using the atomicio callback mechanism add a bandwidth limit option to sftp(1) using the above "very nice" markus@
Diffstat (limited to 'scp.c')
-rw-r--r--scp.c122
1 files changed, 22 insertions, 100 deletions
diff --git a/scp.c b/scp.c
index e07de42f7..a4066c668 100644
--- a/scp.c
+++ b/scp.c
@@ -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
121int do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout); 121int do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout);
122 122
123void bwlimit(int);
124
125/* Struct for addargs */ 123/* Struct for addargs */
126arglist args; 124arglist args;
127 125
128/* Bandwidth limit */ 126/* Bandwidth limit */
129off_t limit_rate = 0; 127long long limit_kbps = 0;
128struct bwlimit bwlimit;
130 129
131/* Name of current file being transferred. */ 130/* Name of current file being transferred. */
132char *curfile; 131char *curfile;
@@ -312,15 +311,14 @@ void sink(int, char *[]);
312void source(int, char *[]); 311void source(int, char *[]);
313void tolocal(int, char *[]); 312void tolocal(int, char *[]);
314void toremote(char *, int, char *[]); 313void toremote(char *, int, char *[]);
315size_t scpio(ssize_t (*)(int, void *, size_t), int, void *, size_t, off_t *);
316void usage(void); 314void usage(void);
317 315
318int 316int
319main(int argc, char **argv) 317main(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 478static int
479 * the progressmeter counter. 479scpio(void *_cnt, size_t s)
480 */
481size_t
482scpio(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
514void 489void
@@ -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
827void 802void
828bwlimit(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
881void
882sink(int argc, char **argv) 803sink(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) :