Rework wget, the xconnect interface, and its various clients
authorEric Andersen <andersen@codepoet.org>
Fri, 31 Oct 2003 09:31:46 +0000 (09:31 -0000)
committerEric Andersen <andersen@codepoet.org>
Fri, 31 Oct 2003 09:31:46 +0000 (09:31 -0000)
in order to fix the problems with round robin DNS reported
by Andrew Flegg:
    http://busybox.net/lists/busybox/2003-October/009579.html

This removes the ipv6 specific xconnect dns lookups.  I do
not see why that would need to be special cased for ipv6 as
was done, but that will just have to be tested.

So IPV6 people -- please test this change!

 -Erik

include/libbb.h
libbb/safe_write.c
libbb/xconnect.c
networking/telnet.c
networking/wget.c
util-linux/rdate.c

index 7587a40..53062de 100644 (file)
@@ -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);
index dd35f35..0ac6c2d 100644 (file)
@@ -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;
 
index 2945d76..2745979 100644 (file)
 #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
 }
index ac6ec98..92ddfae 100644 (file)
@@ -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);
 
index 597d610..0802691 100644 (file)
@@ -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 $
  */
 
 
index 8d156cc..a822f42 100644 (file)
@@ -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);