added --existing option, similar to one suggested by Gildas Quiniou <gildas@stip.fr>
[rsync/rsync.git] / socket.c
index eb25d8c..9a61951 100644 (file)
--- a/socket.c
+++ b/socket.c
@@ -89,10 +89,11 @@ static int establish_proxy_connection(int fd, char *host, int port)
 /* open a socket to a tcp remote host with the specified port 
    based on code from Warren
    proxy support by Stephen Rothwell */
-int open_socket_out(char *host, int port)
+int open_socket_out(char *host, int port, struct in_addr *address)
 {
        int type = SOCK_STREAM;
        struct sockaddr_in sock_out;
+       struct sockaddr_in sock;
        int res;
        struct hostent *hp;
        char *h;
@@ -137,6 +138,13 @@ int open_socket_out(char *host, int port)
        sock_out.sin_port = htons(p);
        sock_out.sin_family = PF_INET;
 
+       if (address) {
+               sock.sin_addr = *address;
+               sock.sin_port = 0;
+               sock.sin_family = hp->h_addrtype;
+               bind(res, (struct sockaddr * ) &sock,sizeof(sock));
+       }
+
        if (connect(res,(struct sockaddr *)&sock_out,sizeof(sock_out))) {
                rprintf(FERROR,"failed to connect to %s - %s\n", h, strerror(errno));
                close(res);
@@ -148,8 +156,6 @@ int open_socket_out(char *host, int port)
                return -1;
        }
 
-       set_nonblocking(res);
-
        return res;
 }
 
@@ -157,7 +163,7 @@ int open_socket_out(char *host, int port)
 /****************************************************************************
 open a socket of the specified type, port and address for incoming data
 ****************************************************************************/
-static int open_socket_in(int type, int port)
+static int open_socket_in(int type, int port, struct in_addr *address)
 {
        struct hostent *hp;
        struct sockaddr_in sock;
@@ -181,7 +187,11 @@ static int open_socket_in(int type, int port)
        memcpy((char *)&sock.sin_addr,(char *)hp->h_addr, hp->h_length);
        sock.sin_port = htons(port);
        sock.sin_family = hp->h_addrtype;
-       sock.sin_addr.s_addr = INADDR_ANY;
+       if (address) {
+               sock.sin_addr = *address;
+       } else {
+               sock.sin_addr.s_addr = INADDR_ANY;
+       }
        res = socket(hp->h_addrtype, type, 0);
        if (res == -1) { 
                rprintf(FERROR,"socket failed\n"); 
@@ -215,9 +225,10 @@ int is_a_socket(int fd)
 void start_accept_loop(int port, int (*fn)(int ))
 {
        int s;
+       extern struct in_addr socket_address;
 
        /* open an incoming socket */
-       s = open_socket_in(SOCK_STREAM, port);
+       s = open_socket_in(SOCK_STREAM, port, &socket_address);
        if (s == -1)
                exit_cleanup(RERR_SOCKETIO);
 
@@ -255,14 +266,12 @@ void start_accept_loop(int port, int (*fn)(int ))
                   but I have had reports that on Digital Unix zombies
                   are produced, so this ensures that they are reaped */
 #ifdef WNOHANG
-               waitpid(-1, NULL, WNOHANG);
+                while (waitpid(-1, NULL, WNOHANG) > 0);
 #endif
 
                if (fork()==0) {
                        close(s);
 
-                       set_nonblocking(fd);
-
                        _exit(fn(fd));
                }
 
@@ -480,3 +489,39 @@ char *client_name(int fd)
 
        return name_buf;
 }
+
+/*******************************************************************
+convert a string to an IP address. The string can be a name or
+dotted decimal number
+  ******************************************************************/
+struct in_addr *ip_address(const char *str)
+{
+       static struct in_addr ret;
+       struct hostent *hp;
+
+       /* try as an IP address */
+       if (inet_aton(str, &ret) != 0) {
+               return &ret;
+       }
+
+       /* otherwise assume it's a network name of some sort and use 
+          gethostbyname */
+       if ((hp = gethostbyname(str)) == 0) {
+               rprintf(FERROR, "gethostbyname: Unknown host. %s\n",str);
+               return NULL;
+       }
+
+       if (hp->h_addr == NULL) {
+               rprintf(FERROR, "gethostbyname: host address is invalid for host %s\n",str);
+               return NULL;
+       }
+
+       if (hp->h_length > sizeof(ret)) {
+               rprintf(FERROR, "gethostbyname: host address is too large\n");
+               return NULL;
+       }
+
+       memcpy(&ret.s_addr, hp->h_addr, hp->h_length);
+
+       return(&ret);
+}