Rework wget, the xconnect interface, and its various clients in order to fix the problems with round robin DNS reported by Andrew Flegg: http://busybox.net/lists/busybox/2003-October/009579.html
No binary (build failed)
—
(log yok)
| @@ -109,9 +109,9 @@ extern int is_directory(const char *name, int followLinks, struct stat *statBuf) | |
| extern int remove_file(const char *path, int flags); | |
| extern int copy_file(const char *source, const char *dest, int flags); | |
| extern ssize_t safe_read(int fd, void *buf, size_t count); | |
| - | extern ssize_t safe_write(int fd, void *buf, size_t count); |
| - | extern ssize_t bb_full_write(int fd, const void *buf, size_t len); |
| extern ssize_t bb_full_read(int fd, void *buf, size_t len); | |
| + | extern ssize_t safe_write(int fd, const void *buf, size_t count); |
| + | extern ssize_t bb_full_write(int fd, const void *buf, size_t len); |
| extern int recursive_action(const char *fileName, int recurse, | |
| int followLinks, int depthFirst, | |
| int (*fileAction) (const char *fileName, struct stat* statbuf, void* userData), | |
| @@ -294,7 +294,9 @@ extern struct hostent *xgethostbyname(const char *name); | |
| extern struct hostent *xgethostbyname2(const char *name, int af); | |
| extern int create_icmp_socket(void); | |
| extern int create_icmp6_socket(void); | |
| - | extern int xconnect(const char *host, const char *port); |
| + | extern int xconnect(struct sockaddr_in *s_addr); |
| + | extern int bb_getport(char *port); |
| + | extern void bb_lookup_host(struct sockaddr_in *s_in, char *host, char *port); |
| //#warning wrap this? | |
| char *dirname (char *path); | |
| @@ -26,7 +26,7 @@ | |
| - | ssize_t safe_write(int fd, void *buf, size_t count) |
| + | ssize_t safe_write(int fd, const void *buf, size_t count) |
| { | |
| ssize_t n; | |
| @@ -11,69 +11,57 @@ | |
| #include <stdlib.h> | |
| #include <sys/types.h> | |
| #include <sys/socket.h> | |
| + | #include <errno.h> |
| #include <netdb.h> | |
| + | #include <sys/socket.h> |
| #include <netinet/in.h> | |
| + | #include <arpa/inet.h> |
| #include "libbb.h" | |
| - | int xconnect(const char *host, const char *port) |
| + | int bb_getport(char *port) |
| { | |
| - | #ifdef CONFIG_FEATURE_IPV6 |
| - | struct addrinfo hints; |
| - | struct addrinfo *res; |
| - | struct addrinfo *addr_info; |
| - | int error; |
| - | int s; |
| + | int port_nr; |
| + | char *endptr; |
| + | struct servent *tserv; |
| - | memset(&hints, 0, sizeof(hints)); |
| - | /* set-up hints structure */ |
| - | hints.ai_family = PF_UNSPEC; |
| - | hints.ai_socktype = SOCK_STREAM; |
| - | error = getaddrinfo(host, port, &hints, &res); |
| - | if (error||!res) |
| - | bb_perror_msg_and_die(gai_strerror(error)); |
| - | addr_info=res; |
| - | while (res) { |
| - | s=socket(res->ai_family, res->ai_socktype, res->ai_protocol); |
| - | if (s<0) |
| - | { |
| - | error=s; |
| - | res=res->ai_next; |
| - | continue; |
| - | } |
| - | /* try to connect() to res->ai_addr */ |
| - | error = connect(s, res->ai_addr, res->ai_addrlen); |
| - | if (error >= 0) |
| - | break; |
| - | close(s); |
| - | res=res->ai_next; |
| + | if (!port) { |
| + | return -1; |
| } | |
| - | freeaddrinfo(addr_info); |
| - | if (error < 0) |
| + | port_nr=strtol(port, &endptr, 10); |
| + | if (errno != 0 || *endptr!='\0' || endptr==port || port_nr < 1 || port_nr > 65536) |
| { | |
| - | bb_perror_msg_and_die("Unable to connect to remote host (%s)", host); |
| + | if (port_nr==0 && (tserv = getservbyname(port, "tcp")) != NULL) { |
| + | port_nr = tserv->s_port; |
| + | } else { |
| + | return -1; |
| + | } |
| + | } else { |
| + | port_nr = htons(port_nr); |
| } | |
| - | return s; |
| - | #else |
| - | struct sockaddr_in s_addr; |
| - | int s = socket(AF_INET, SOCK_STREAM, 0); |
| - | struct servent *tserv; |
| - | int port_nr=htons(atoi(port)); |
| - | struct hostent * he; |
| - | |
| - | if (port_nr==0 && (tserv = getservbyname(port, "tcp")) != NULL) |
| - | port_nr = tserv->s_port; |
| + | return port_nr; |
| + | } |
| - | memset(&s_addr, 0, sizeof(struct sockaddr_in)); |
| - | s_addr.sin_family = AF_INET; |
| - | s_addr.sin_port = port_nr; |
| + | void bb_lookup_host(struct sockaddr_in *s_in, char *host, char *port) |
| + | { |
| + | struct hostent *he; |
| + | memset(s_in, 0, sizeof(struct sockaddr_in)); |
| + | s_in->sin_family = AF_INET; |
| he = xgethostbyname(host); | |
| - | memcpy(&s_addr.sin_addr, he->h_addr, sizeof s_addr.sin_addr); |
| + | memcpy(&(s_in->sin_addr), he->h_addr_list[0], he->h_length); |
| - | if (connect(s, (struct sockaddr *)&s_addr, sizeof s_addr) < 0) |
| + | if (port) { |
| + | s_in->sin_port=bb_getport(port); |
| + | } |
| + | } |
| + | |
| + | int xconnect(struct sockaddr_in *s_addr) |
| + | { |
| + | int s = socket(AF_INET, SOCK_STREAM, 0); |
| + | if (connect(s, (struct sockaddr_in *)s_addr, sizeof(struct sockaddr_in)) < 0) |
| { | |
| - | bb_perror_msg_and_die("Unable to connect to remote host (%s)", host); |
| + | bb_perror_msg_and_die("Unable to connect to remote host (%s)", |
| + | inet_ntoa(s_addr->sin_addr)); |
| } | |
| return s; | |
| - | #endif |
| } | |
| @@ -573,6 +573,7 @@ extern int telnet_main(int argc, char** argv) | |
| char *host; | |
| char *port; | |
| int len; | |
| + | struct sockaddr_in s_in; |
| #ifdef USE_POLL | |
| struct pollfd ufds[2]; | |
| #else | |
| @@ -601,7 +602,8 @@ extern int telnet_main(int argc, char** argv) | |
| host = argv[1]; | |
| - | G.netfd = xconnect(host, port); |
| + | bb_lookup_host(&s_in, host, port); |
| + | G.netfd = xconnect(&s_in); |
| setsockopt(G.netfd, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof one); | |
| @@ -40,7 +40,7 @@ struct host_info { | |
| }; | |
| static void parse_url(char *url, struct host_info *h); | |
| - | static FILE *open_socket(char *host, int port); |
| + | static FILE *open_socket(struct sockaddr_in *s_in, int port); |
| static char *gethdr(char *buf, size_t bufsiz, FILE *fp, int *istrunc); | |
| static int ftpcmd(char *s1, char *s2, FILE *fp, char *buf); | |
| @@ -155,6 +155,7 @@ int wget_main(int argc, char **argv) | |
| int extra_headers_left = sizeof(extra_headers); | |
| int which_long_opt = 0, option_index = -1; | |
| struct host_info server, target; | |
| + | struct sockaddr_in s_in; |
| FILE *sfp = NULL; /* socket to web/ftp server */ | |
| FILE *dfp = NULL; /* socket to ftp server (data) */ | |
| @@ -290,6 +291,15 @@ int wget_main(int argc, char **argv) | |
| do_continue = 0; | |
| } | |
| + | /* We want to do exactly _one_ DNS lookup, since some |
| + | * sites (i.e. ftp.us.debian.org) use round-robin DNS |
| + | * and we want to connect to only one IP... */ |
| + | bb_lookup_host(&s_in, server.host, NULL); |
| + | if (quiet_flag==FALSE) { |
| + | fprintf(stdout, "Connecting to %s[%s]:%d\n", |
| + | server.host, inet_ntoa(s_in.sin_addr), server.port); |
| + | } |
| + | |
| if (proxy || !target.is_ftp) { | |
| /* | |
| * HTTP session | |
| @@ -304,7 +314,7 @@ int wget_main(int argc, char **argv) | |
| * Open socket to http server | |
| */ | |
| if (sfp) fclose(sfp); | |
| - | sfp = open_socket(server.host, server.port); |
| + | sfp = open_socket(&s_in, server.port); |
| /* | |
| * Send HTTP request. | |
| @@ -416,7 +426,7 @@ read_response: | |
| if (! target.user) | |
| target.user = bb_xstrdup("anonymous:busybox@"); | |
| - | sfp = open_socket(server.host, server.port); |
| + | sfp = open_socket(&s_in, server.port); |
| if (ftpcmd(NULL, NULL, sfp, buf) != 220) | |
| close_delete_and_die("%s", buf+4); | |
| @@ -459,7 +469,7 @@ read_response: | |
| port = atoi(s+1); | |
| s = strrchr(buf, ','); | |
| port += atoi(s+1) * 256; | |
| - | dfp = open_socket(server.host, port); |
| + | dfp = open_socket(&s_in, port); |
| if (do_continue) { | |
| sprintf(buf, "REST %ld", beg_range); | |
| @@ -584,14 +594,16 @@ void parse_url(char *url, struct host_info *h) | |
| } | |
| - | FILE *open_socket(char *host, int port) |
| + | FILE *open_socket(struct sockaddr_in *s_in, int port) |
| { | |
| int fd; | |
| FILE *fp; | |
| - | char port_str[10]; |
| - | snprintf(port_str, sizeof(port_str), "%d", port); |
| - | fd=xconnect(host, port_str); |
| + | if (port>0 && port < 65536) { |
| + | s_in->sin_port=htons(port); |
| + | } |
| + | |
| + | fd=xconnect(s_in); |
| /* | |
| * Get the server onto a stdio stream. | |
| @@ -838,7 +850,7 @@ progressmeter(int flag) | |
| * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| * SUCH DAMAGE. | |
| * | |
| - | * $Id: wget.c,v 1.60 2003/09/15 08:33:37 andersen Exp $ |
| + | * $Id: wget.c,v 1.61 2003/10/31 09:31:43 andersen Exp $ |
| */ | |
| @@ -47,17 +47,16 @@ static void socket_timeout(int sig) | |
| static time_t askremotedate(const char *host) | |
| { | |
| unsigned long int nett, localt; | |
| - | const char *port="37"; |
| + | struct sockaddr_in addr s_in; |
| int fd; | |
| - | if (getservbyname("time", "tcp") != NULL) |
| - | port="time"; |
| + | bb_lookup_host(&s_in, host, "time"); |
| /* Add a timeout for dead or non accessable servers */ | |
| alarm(10); | |
| signal(SIGALRM, socket_timeout); | |
| - | fd = xconnect(host, port); |
| + | fd = xconnect(s_in); |
| if (safe_read(fd, (void *)&nett, 4) != 4) /* read time from server */ | |
| bb_error_msg_and_die("%s did not send the complete time", host); | |