From 13e29995f5f08300ea946374079dff50f8cb6bd7 Mon Sep 17 00:00:00 2001 From: Martin Pool Date: Tue, 18 Dec 2001 05:54:57 +0000 Subject: [PATCH] Get rid of global_opts struct as suggested by Dave -- too many problems with initialization. Change the algorithm from trying to open an inbound socket with getaddrinfo: keep trying suggested addresses until we find one on which we can both get a socket and bind. Not convinced this is the best, but it's probably better. --- clientserver.c | 6 +++-- options.c | 29 +++++++++++---------- socket.c | 69 +++++++++++++++++++++----------------------------- 3 files changed, 49 insertions(+), 55 deletions(-) diff --git a/clientserver.c b/clientserver.c index 1b3801bc..73893764 100644 --- a/clientserver.c +++ b/clientserver.c @@ -45,6 +45,7 @@ int start_socket_client(char *host, char *path, int argc, char *argv[]) extern char *shell_cmd; extern int kludge_around_eof; extern char *bind_address; + extern int default_af_hint; if (argc == 0 && !am_sender) { extern int list_only; @@ -79,7 +80,7 @@ int start_socket_client(char *host, char *path, int argc, char *argv[]) if (!user) user = getenv("LOGNAME"); fd = open_socket_out_wrapped (host, rsync_port, bind_address, - global_opts.af_hint); + default_af_hint); if (fd == -1) { exit_cleanup(RERR_SOCKETIO); } @@ -486,6 +487,7 @@ int daemon_main(void) extern char *config_file; extern int orig_umask; char *pid_file; + extern int no_detach; if (is_a_socket(STDIN_FILENO)) { int i; @@ -501,7 +503,7 @@ int daemon_main(void) return start_daemon(STDIN_FILENO); } - if (!global_opts.no_detach) + if (!no_detach) become_daemon(); if (!lp_load(config_file, 1)) { diff --git a/options.c b/options.c index 9bb22f45..8893195a 100644 --- a/options.c +++ b/options.c @@ -74,18 +74,21 @@ int modify_window=0; #endif int blocking_io=0; -/** Global options set from command line. **/ -struct global_opts global_opts = { +/** Network address family. **/ #ifdef INET6 - 0, /* af_hint -- allow any protocol */ +int default_af_hint = 0; /* Any protocol */ #else - AF_INET, /* af_hint -- prefer IPv4 */ +int default_af_hint = AF_INET; /* Must use IPv4 */ #endif - 0, /* no_detach */ -}; -int read_batch=0; /* dw */ -int write_batch=0; /* dw */ +/** Do not go into the background when run as --daemon. Good + * for debugging and required for running as a service on W32, + * or under Unix process-monitors. **/ +int no_detach = 0; + + +int read_batch=0; +int write_batch=0; char *backup_suffix = BACKUP_SUFFIX; char *tmpdir = NULL; @@ -178,8 +181,8 @@ void usage(enum logcode F) rprintf(F," --backup-dir make backups into this directory\n"); rprintf(F," --suffix=SUFFIX override backup suffix\n"); rprintf(F," -u, --update update only (don't overwrite newer files)\n"); - rprintf(F," -l, --links preserve soft links\n"); - rprintf(F," -L, --copy-links treat soft links like regular files\n"); + rprintf(F," -l, --links copy symlinks as symlinks\n"); + rprintf(F," -L, --copy-links copy the referent of symlinks\n"); rprintf(F," --copy-unsafe-links copy links outside the source tree\n"); rprintf(F," --safe-links ignore links outside the destination tree\n"); rprintf(F," -H, --hard-links preserve hard links\n"); @@ -306,7 +309,7 @@ static struct poptOption long_options[] = { /* TODO: Should this take an optional int giving the compression level? */ {"compress", 'z', POPT_ARG_NONE, &do_compression}, {"daemon", 0, POPT_ARG_NONE, &am_daemon}, - {"no-detach", 0, POPT_ARG_NONE, &global_opts.no_detach}, + {"no-detach", 0, POPT_ARG_NONE, &no_detach}, {"stats", 0, POPT_ARG_NONE, &do_stats}, {"progress", 0, POPT_ARG_NONE, &do_progress}, {"partial", 0, POPT_ARG_NONE, &keep_partial}, @@ -323,8 +326,8 @@ static struct poptOption long_options[] = { {"read-batch", 'f', POPT_ARG_STRING, &batch_ext, 'f'}, {"write-batch", 'F', POPT_ARG_NONE, &write_batch, 0}, #ifdef INET6 - {0, '4', POPT_ARG_VAL, &global_opts.af_hint, AF_INET }, - {0, '6', POPT_ARG_VAL, &global_opts.af_hint, AF_INET6 }, + {0, '4', POPT_ARG_VAL, &default_af_hint, AF_INET }, + {0, '6', POPT_ARG_VAL, &default_af_hint, AF_INET6 }, #endif {0,0,0,0} }; diff --git a/socket.c b/socket.c index 0ad8a169..850cb144 100644 --- a/socket.c +++ b/socket.c @@ -267,7 +267,7 @@ static int open_socket_in(int type, int port, const char *bind_address, { int one=1; int s; - struct addrinfo hints, *res, *resp; + struct addrinfo hints, *all_ai, *resp; char portbuf[10]; int error; @@ -276,54 +276,43 @@ static int open_socket_in(int type, int port, const char *bind_address, hints.ai_socktype = type; hints.ai_flags = AI_PASSIVE; snprintf(portbuf, sizeof(portbuf), "%d", port); - error = getaddrinfo(bind_address, portbuf, &hints, &res); + error = getaddrinfo(bind_address, portbuf, &hints, &all_ai); if (error) { rprintf(FERROR, RSYNC_NAME ": getaddrinfo: bind address %s: %s\n", bind_address, gai_strerror(error)); return -1; } - /* XXX: Do we need to care about getting multiple results - * back? I think probably not; if the user passed - * bind_address == NULL and we set AI_PASSIVE then we ought to - * get a wildcard result. */ - resp = res; - while (1) { - s = socket(resp->ai_family, resp->ai_socktype, resp->ai_protocol); - - if (s >= 0) { - break; /* got a socket */ - } else if ((resp = resp->ai_next)) { - switch (errno) { - case EPROTONOSUPPORT: - case EAFNOSUPPORT: - case EPFNOSUPPORT: - case EINVAL: - /* See if there's another address that will work... */ - continue; - } + /* We may not be able to create the socket, if for example the + * machine knows about IPv6 in the C library, but not in the + * kernel. */ + for (resp = all_ai; resp; resp = resp->ai_next) { + s = socket(resp->ai_family, resp->ai_socktype, + resp->ai_protocol); + + if (s == -1) + /* See if there's another address that will work... */ + continue; + + setsockopt(s, SOL_SOCKET, SO_REUSEADDR, + (char *)&one, sizeof one); + + /* now we've got a socket - we need to bind it */ + if (bind(s, all_ai->ai_addr, all_ai->ai_addrlen) < 0) { + /* Nope, try another */ + close(s); + continue; } - rprintf(FERROR, RSYNC_NAME ": open inbound socket" - "(dom=%d, type=%d, proto=%d) failed: %s\n", - resp->ai_family, resp->ai_socktype, resp->ai_protocol, - strerror(errno)); - goto fail; + return s; } - setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(one)); - - /* now we've got a socket - we need to bind it */ - if (bind(s, res->ai_addr, res->ai_addrlen) < 0) { - rprintf(FERROR, RSYNC_NAME ": bind failed on port %d\n", port); - close(s); - goto fail; - } - - return s; + rprintf(FERROR, RSYNC_NAME ": open inbound socket on port %d failed: " + "%s\n", + port, + strerror(errno)); -fail: - freeaddrinfo(res); + freeaddrinfo(all_ai); return -1; } @@ -358,10 +347,10 @@ void start_accept_loop(int port, int (*fn)(int )) { int s; extern char *bind_address; + extern int default_af_hint; /* open an incoming socket */ - s = open_socket_in(SOCK_STREAM, port, bind_address, - global_opts.af_hint); + s = open_socket_in(SOCK_STREAM, port, bind_address, default_af_hint); if (s == -1) exit_cleanup(RERR_SOCKETIO); -- 2.34.1