On Tue, Aug 02, 2022 at 12:42:26PM +0000, Job Snijders wrote: > Hi all, > > This adds '--contimeout' to rsync(1) > > $ time openrsync --contimeout=5 -rt rsync://203.119.21.1/test /tmp/k > openrsync: warning: connect timeout: 203.119.21.1, 203.119.21.1 > openrsync: error: cannot connect to host: 203.119.21.1 > 0m05.01s real 0m00.00s user 0m00.01s system > > OK? > > Kind regards, > > Job > > Index: extern.h > =================================================================== > RCS file: /cvs/src/usr.bin/rsync/extern.h,v > retrieving revision 1.43 > diff -u -p -r1.43 extern.h > --- extern.h 29 Oct 2021 08:00:59 -0000 1.43 > +++ extern.h 2 Aug 2022 12:34:49 -0000 > @@ -70,6 +70,11 @@ > extern int poll_timeout; > > /* > + * Use this for --contimeout. > + */ > +extern int poll_contimeout; > + > +/* > * Operating mode for a client or a server. > * Sender means we synchronise local files with those from remote. > * Receiver is the opposite. > Index: main.c > =================================================================== > RCS file: /cvs/src/usr.bin/rsync/main.c,v > retrieving revision 1.63 > diff -u -p -r1.63 main.c > --- main.c 3 Nov 2021 14:42:12 -0000 1.63 > +++ main.c 2 Aug 2022 12:34:49 -0000 > @@ -31,6 +31,7 @@ > #include "extern.h" > > int verbose; > +int poll_contimeout; > int poll_timeout; > > /* > @@ -286,6 +287,7 @@ static struct opts opts; > #define OP_LINK_DEST 1011 > #define OP_MAX_SIZE 1012 > #define OP_MIN_SIZE 1013 > +#define OP_CONTIMEOUT 1014 > > const struct option lopts[] = { > { "address", required_argument, NULL, OP_ADDRESS }, > @@ -296,6 +298,7 @@ const struct option lopts[] = { > { "link-dest", required_argument, NULL, OP_LINK_DEST }, > #endif > { "compress", no_argument, NULL, 'z' }, > + { "contimeout", required_argument, NULL, OP_CONTIMEOUT }, > { "del", no_argument, &opts.del, 1 }, > { "delete", no_argument, &opts.del, 1 }, > { "devices", no_argument, &opts.devices, 1 }, > @@ -411,6 +414,12 @@ main(int argc, char *argv[]) > case OP_ADDRESS: > opts.address = optarg; > break; > + case OP_CONTIMEOUT: > + poll_contimeout = strtonum(optarg, 0, 60*60, &errstr); > + if (errstr != NULL) > + errx(ERR_SYNTAX, "timeout is %s: %s", > + errstr, optarg); > + break; > case OP_PORT: > opts.port = optarg; > break; > @@ -503,9 +512,16 @@ basedir: > if (opts.port == NULL) > opts.port = "rsync"; > > + /* by default and for --contimeout=0 disable poll_contimeout */ > + if (poll_contimeout == 0) > + poll_contimeout = -1; > + else > + poll_contimeout *= 1000; > + > /* by default and for --timeout=0 disable poll_timeout */ > if (poll_timeout == 0) > - poll_timeout = -1; else > + poll_timeout = -1; > + else > poll_timeout *= 1000; > > /* > @@ -614,10 +630,11 @@ basedir: > usage: > fprintf(stderr, "usage: %s" > " [-aDglnoprtvx] [-e program] [--address=sourceaddr]\n" > - "\t[--compare-dest=dir] [--del] [--exclude] [--exclude-from=file]\n" > - "\t[--include] [--include-from=file] [--no-motd] [--numeric-ids]\n" > - "\t[--port=portnumber] [--rsync-path=program] [--timeout=seconds]\n" > - "\t[--version] source ... directory\n", > + "\t[--contimeout=seconds [--compare-dest=dir] [--del] [--exclude]\n" > + "\t[--exclude-from=file] [--include] [--include-from=file]\n" > + "\t[--no-motd] [--numeric-ids] [--port=portnumber]\n" > + "\t[--rsync-path=program] [--timeout=seconds] [--version]\n" > + "\tsource ... directory\n", > getprogname()); > exit(ERR_SYNTAX); > } > Index: rsync.1 > =================================================================== > RCS file: /cvs/src/usr.bin/rsync/rsync.1,v > retrieving revision 1.29 > diff -u -p -r1.29 rsync.1 > --- rsync.1 26 Nov 2021 03:41:39 -0000 1.29 > +++ rsync.1 2 Aug 2022 12:34:49 -0000 > @@ -26,6 +26,7 @@ > .Op Fl e Ar program > .Op Fl -address Ns = Ns Ar sourceaddr > .Op Fl -compare-dest Ns = Ns Ar directory > +.Op Fl -contimeout Ns = Ns Ar seconds > .Op Fl -del > .Op Fl -exclude Ar pattern > .Op Fl -exclude-from Ns = Ns Ar file > @@ -77,6 +78,10 @@ directories may be provided. > If > .Ar directory > is a relative path, it is relative to the destination directory. > +.It Fl -contimeout Ns = Ns Ar seconds > +Set the connection timeout in seconds. > +Exit if no connection established within the specified time. > +The default is 0, which means no timeout. > .It Fl D > Also transfer device and special files. > Shorthand for > Index: socket.c > =================================================================== > RCS file: /cvs/src/usr.bin/rsync/socket.c,v > retrieving revision 1.31 > diff -u -p -r1.31 socket.c > --- socket.c 30 Jun 2021 13:10:04 -0000 1.31 > +++ socket.c 2 Aug 2022 12:34:49 -0000 > @@ -75,14 +75,18 @@ static int > inet_connect(int *sd, const struct source *src, const char *host, > const struct source *bsrc, size_t bsrcsz) > { > - int c, flags; > + struct pollfd pfd; > + socklen_t optlen; > + int c, flags; > + int optval; > > if (*sd != -1) > close(*sd); > > LOG2("trying: %s, %s", src->ip, host); > > - if ((*sd = socket(src->family, SOCK_STREAM, 0)) == -1) { > + if ((*sd = socket(src->family, SOCK_STREAM | SOCK_NONBLOCK, 0)) > + == -1) { > ERR("socket"); > return -1; > } > @@ -99,8 +103,28 @@ inet_connect(int *sd, const struct sourc > * while waiting for this to finish. > */ > > - c = connect(*sd, (const struct sockaddr *)&src->sa, src->salen); > + if ((c = connect(*sd, (const struct sockaddr *)&src->sa, src->salen)) > + != 0 && errno == EINPROGRESS) { > + pfd.fd = *sd; > + pfd.events = POLLOUT; > + if ((c = poll(&pfd, 1, poll_contimeout)) == 1) { > + optlen = sizeof(optval); > + if ((c = getsockopt(*sd, SOL_SOCKET, SO_ERROR, &optval, > + &optlen)) == 0) { > + errno = optval; > + c = optval == 0 ? 0 : -1; > + } > + } else if (c == 0) { > + errno = ETIMEDOUT; > + c = -1; > + } else > + err(1, "poll failed"); > + } > if (c == -1) { > + if (errno == ETIMEDOUT) { > + WARNX("connect timeout: %s, %s", src->ip, host); > + return 0; > + } > if (errno == EADDRNOTAVAIL) > return 0; > if (errno == ECONNREFUSED || errno == EHOSTUNREACH) { >
You make the socket non-blocking by default. Please remove the fcntl at the end of the function. There is no need to double up the non-blocking here. Also I would move the ETIMEDOUT handling up into the connect block. No need to do this complicated errno game. You can use a switch for the poll call: switch (poll()) { case 0, case 1, default). I don't like how c is used over and over again. -- :wq Claudio