mirror of
https://github.com/RsyncProject/rsync.git
synced 2026-03-03 05:46:02 -05:00
Applied a slightly-tweaked version of Oliver Braun's patch that
implements listening on multiple addresses and a fix for IPv6-only systems.
This commit is contained in:
96
socket.c
96
socket.c
@@ -285,11 +285,11 @@ int open_socket_out_wrapped(char *host, int port, const char *bind_address,
|
||||
* @param bind_address Local address to bind, or NULL to allow it to
|
||||
* default.
|
||||
**/
|
||||
static int open_socket_in(int type, int port, const char *bind_address,
|
||||
int af_hint)
|
||||
static int *open_socket_in(int type, int port, const char *bind_address,
|
||||
int af_hint)
|
||||
{
|
||||
int one=1;
|
||||
int s;
|
||||
int s, *sp, *socks, maxs;
|
||||
struct addrinfo hints, *all_ai, *resp;
|
||||
char portbuf[10];
|
||||
int error;
|
||||
@@ -303,23 +303,41 @@ static int open_socket_in(int type, int port, const char *bind_address,
|
||||
if (error) {
|
||||
rprintf(FERROR, RSYNC_NAME ": getaddrinfo: bind address %s: %s\n",
|
||||
bind_address, gai_strerror(error));
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Count max number of sockets we might open. */
|
||||
for (maxs = 0, resp = all_ai; resp; resp = resp->ai_next, maxs++) {}
|
||||
socks = new_array(int, maxs + 1);
|
||||
if (!socks) {
|
||||
rprintf(FERROR,
|
||||
RSYNC_NAME "couldn't allocate memory for sockets");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
sp = socks + 1; /* Leave room for count at start of array. */
|
||||
for (resp = all_ai; resp; resp = resp->ai_next) {
|
||||
s = socket(resp->ai_family, resp->ai_socktype,
|
||||
resp->ai_protocol);
|
||||
|
||||
if (s == -1)
|
||||
if (s == -1) {
|
||||
/* See if there's another address that will work... */
|
||||
continue;
|
||||
}
|
||||
|
||||
setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
|
||||
(char *)&one, sizeof one);
|
||||
|
||||
#ifdef IPV6_V6ONLY
|
||||
if (resp->ai_family == AF_INET6) {
|
||||
setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
|
||||
(char *)&one, sizeof one);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Now we've got a socket - we need to bind it. */
|
||||
if (bind(s, resp->ai_addr, resp->ai_addrlen) < 0) {
|
||||
/* Nope, try another */
|
||||
@@ -327,17 +345,21 @@ static int open_socket_in(int type, int port, const char *bind_address,
|
||||
continue;
|
||||
}
|
||||
|
||||
freeaddrinfo(all_ai);
|
||||
return s;
|
||||
*sp++ = s;
|
||||
}
|
||||
*socks = sp - socks - 1; /* Save count. */
|
||||
|
||||
rprintf(FERROR, RSYNC_NAME ": open inbound socket on port %d failed: "
|
||||
"%s\n",
|
||||
port,
|
||||
strerror(errno));
|
||||
if (all_ai)
|
||||
freeaddrinfo(all_ai);
|
||||
|
||||
freeaddrinfo(all_ai);
|
||||
return -1;
|
||||
if (*socks == 0) {
|
||||
rprintf(FERROR,
|
||||
RSYNC_NAME ": open inbound socket on port %d failed: "
|
||||
"%s\n", port, strerror(errno));
|
||||
free(socks);
|
||||
return NULL;
|
||||
}
|
||||
return socks;
|
||||
}
|
||||
|
||||
|
||||
@@ -378,19 +400,29 @@ static RETSIGTYPE sigchld_handler(UNUSED(int val))
|
||||
|
||||
void start_accept_loop(int port, int (*fn)(int, int))
|
||||
{
|
||||
int s;
|
||||
fd_set deffds;
|
||||
int *sp, maxfd, i, j;
|
||||
extern char *bind_address;
|
||||
extern int default_af_hint;
|
||||
|
||||
/* open an incoming socket */
|
||||
s = open_socket_in(SOCK_STREAM, port, bind_address, default_af_hint);
|
||||
if (s == -1)
|
||||
sp = open_socket_in(SOCK_STREAM, port, bind_address, default_af_hint);
|
||||
if (sp == NULL)
|
||||
exit_cleanup(RERR_SOCKETIO);
|
||||
|
||||
/* ready to listen */
|
||||
if (listen(s, 5) == -1) {
|
||||
close(s);
|
||||
exit_cleanup(RERR_SOCKETIO);
|
||||
FD_ZERO(&deffds);
|
||||
maxfd = -1;
|
||||
for (i = 1; i <= *sp; i++) {
|
||||
if (listen(sp[i], 5) == -1) {
|
||||
for (j = 1; j <= i; j++)
|
||||
close(sp[j]);
|
||||
free(sp);
|
||||
exit_cleanup(RERR_SOCKETIO);
|
||||
}
|
||||
FD_SET(sp[i], &deffds);
|
||||
if (maxfd < sp[i])
|
||||
maxfd = sp[i];
|
||||
}
|
||||
|
||||
|
||||
@@ -408,25 +440,32 @@ void start_accept_loop(int port, int (*fn)(int, int))
|
||||
forever */
|
||||
log_close();
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(s, &fds);
|
||||
#ifdef FD_COPY
|
||||
FD_COPY(&deffds, &fds);
|
||||
#else
|
||||
fds = deffds;
|
||||
#endif
|
||||
|
||||
if (select(s+1, &fds, NULL, NULL, NULL) != 1)
|
||||
if (select(maxfd + 1, &fds, NULL, NULL, NULL) != 1)
|
||||
continue;
|
||||
|
||||
if (!FD_ISSET(s, &fds))
|
||||
continue;
|
||||
fd = -1;
|
||||
for (i = 1; i <= *sp; i++) {
|
||||
if (FD_ISSET(sp[i], &fds)) {
|
||||
fd = accept(sp[i], (struct sockaddr *)&addr,
|
||||
&addrlen);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fd = accept(s,(struct sockaddr *)&addr,&addrlen);
|
||||
|
||||
if (fd == -1)
|
||||
if (fd < 0)
|
||||
continue;
|
||||
|
||||
signal(SIGCHLD, sigchld_handler);
|
||||
|
||||
if ((pid = fork()) == 0) {
|
||||
int ret;
|
||||
close(s);
|
||||
close(sp[i]);
|
||||
/* open log file in child before possibly giving
|
||||
up privileges */
|
||||
log_open();
|
||||
@@ -448,6 +487,7 @@ void start_accept_loop(int port, int (*fn)(int, int))
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
free(sp);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user