X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/0503f06089b89aa4166d6ced8d5901ad6a112c41..af642a61b369ae6e488d674e17aa5242ae9d34d1:/socket.c diff --git a/socket.c b/socket.c index 4c81d597..2aa8481a 100644 --- a/socket.c +++ b/socket.c @@ -1,5 +1,6 @@ -/* - Copyright (C) Andrew Tridgell 1998 +/* -*- c-file-style: "linux" -*- + + Copyright (C) 1998-2000 by Andrew Tridgell This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -89,10 +90,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 +139,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 +157,6 @@ int open_socket_out(char *host, int port) return -1; } - set_nonblocking(res); - return res; } @@ -157,7 +164,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 +188,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"); @@ -201,13 +212,27 @@ static int open_socket_in(int type, int port) } -/**************************************************************************** -determine if a file descriptor is in fact a socket -****************************************************************************/ +/* + * Determine if a file descriptor is in fact a socket + */ int is_a_socket(int fd) { - int v,l; + int v, l; l = sizeof(int); + + /* Parameters to getsockopt, setsockopt etc are very + * unstandardized across platforms, so don't be surprised if + * there are compiler warnings on e.g. SCO OpenSwerver. It + * seems they all eventually get the right idea. + * + * Debian says: ``The fifth argument of getsockopt and + * setsockopt is in reality an int [*] (and this is what BSD + * 4.* and libc4 and libc5 have). Some POSIX confusion + * resulted in the present socklen_t. The draft standard has + * not been adopted yet, but glibc2 already follows it and + * also has socklen_t [*]. See also accept(2).'' + * + * We now return to your regularly scheduled programming. */ return(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&v, &l) == 0); } @@ -215,9 +240,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); @@ -236,6 +262,11 @@ void start_accept_loop(int port, int (*fn)(int )) struct sockaddr addr; int in_addrlen = sizeof(addr); + /* close log file before the potentially very long select so + file can be trimmed by another process instead of growing + forever */ + log_close(); + FD_ZERO(&fds); FD_SET(s, &fds); @@ -245,6 +276,7 @@ void start_accept_loop(int port, int (*fn)(int )) if(!FD_ISSET(s, &fds)) continue; + /* See note above prototypes. */ fd = accept(s,&addr,&in_addrlen); if (fd == -1) continue; @@ -261,7 +293,9 @@ void start_accept_loop(int port, int (*fn)(int )) if (fork()==0) { close(s); - set_nonblocking(fd); + /* open log file in child before possibly giving + up privileges */ + log_open(); _exit(fn(fd)); } @@ -480,3 +514,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); +}