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

Reply via email to