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) {

Reply via email to