#include "rsync.h"
+extern char *bind_address;
+extern int default_af_hint;
/**
* Establish a proxy connection on an open socket to a web proxy by
/**
- * Open a socket of the specified type, port and address for incoming data
+ * Open one or more sockets for incoming data using the specified type,
+ * port, and address.
*
- * Try to be better about handling the results of getaddrinfo(): when
- * opening an inbound socket, we might get several address results,
- * e.g. for the machine's IPv4 and IPv6 name.
+ * The getaddrinfo() call may return several address results, e.g. for
+ * the machine's IPv4 and IPv6 name.
*
- * We return an array of socket file-descriptors, with the length of
- * the array stored as the first element of the list. This allows
- * the caller to listen on all of them.
+ * We return an array of file-descriptors to the sockets, with a trailing
+ * -1 value to indicate the end of the list.
*
* @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)
{
- int one=1;
- int s, *sp, *socks, maxs;
+ int one = 1;
+ int s, *socks, maxs, i;
struct addrinfo hints, *all_ai, *resp;
char portbuf[10];
int error;
/* 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;
- }
+
+ if (!(socks = new_array(int, maxs + 1)))
+ out_of_memory("open_socket_in");
/* 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) {
+ for (resp = all_ai, i = 0; resp; resp = resp->ai_next) {
s = socket(resp->ai_family, resp->ai_socktype,
resp->ai_protocol);
#ifdef IPV6_V6ONLY
if (resp->ai_family == AF_INET6) {
- if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
- (char *)&one, sizeof one) < 0) {
- close(s);
- continue;
- }
+ setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
+ (char *)&one, sizeof one);
}
#endif
continue;
}
- *sp++ = s;
+ socks[i++] = s;
}
- *socks = sp - socks - 1; /* Save count. */
+ socks[i] = -1;
if (all_ai)
freeaddrinfo(all_ai);
- if (*socks == 0) {
+ if (!i) {
rprintf(FERROR,
- RSYNC_NAME ": open inbound socket on port %d failed: "
- "%s\n", port, strerror(errno));
+ "unable to bind any inbound sockets on port %d\n",
+ port);
free(socks);
return NULL;
}
{
fd_set deffds;
int *sp, maxfd, i;
- extern char *bind_address;
- extern int default_af_hint;
/* open an incoming socket */
sp = open_socket_in(SOCK_STREAM, port, bind_address, default_af_hint);
/* ready to listen */
FD_ZERO(&deffds);
- maxfd = -1;
- for (i = 1; i <= *sp; i++) {
- if (listen(sp[i], 5) == -1) {
+ for (i = 0, maxfd = -1; sp[i] >= 0; i++) {
+ if (listen(sp[i], 5) < 0) {
+ rprintf(FERROR, "listen() on socket failed: %s\n",
+ strerror(errno));
+#ifdef INET6
+ if (errno == EADDRINUSE && i > 0) {
+ rprintf(FINFO,
+ "Try using --ipv4 or --ipv6 to avoid this listen() error.");
+ }
+#endif
exit_cleanup(RERR_SOCKETIO);
}
FD_SET(sp[i], &deffds);
if (select(maxfd + 1, &fds, NULL, NULL, NULL) != 1)
continue;
- fd = -1;
- for (i = 1; i <= *sp; i++) {
+ for (i = 0, fd = -1; sp[i] >= 0; i++) {
if (FD_ISSET(sp[i], &fds)) {
fd = accept(sp[i], (struct sockaddr *)&addr,
&addrlen);
if ((pid = fork()) == 0) {
int ret;
- close(sp[i]);
+ for (i = 0; sp[i] >= 0; i++)
+ close(sp[i]);
/* open log file in child before possibly giving
* up privileges */
log_open();