mirror of
https://github.com/RsyncProject/rsync.git
synced 2026-10-27 16:18:16 -04:00
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.
This commit is contained in:
1 parent
7c583c7316
commit
13e29995f5
3 files changed
+48
-54
No files matched your search
+4
-2
@@ -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)) {
|
||||
|
||||
@@ -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}
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
/* 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 >= 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;
|
||||
}
|
||||
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));
|
||||
rprintf(FERROR, RSYNC_NAME ": open inbound socket on port %d failed: "
|
||||
"%s\n",
|
||||
port,
|
||||
strerror(errno));
|
||||
|
||||
/* 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;
|
||||
|
||||
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);
|
||||
|
||||
|
||||
Reference in new issue
Block a user