]> sjero.net Git - wget/blobdiff - src/connect.c
[svn] Treat the "shortcut icon" link as inline.
[wget] / src / connect.c
index 175db605121680096a549a5d1f9cf4e3c5c458b3..28d2f6aa3395a5b37c904a0717286ed562490661 100644 (file)
@@ -1,20 +1,20 @@
 /* Establishing and handling network connections.
    Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
 
-This file is part of Wget.
+This file is part of GNU Wget.
 
-This program is free software; you can redistribute it and/or modify
+GNU Wget is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or
 (at your option) any later version.
 
-This program is distributed in the hope that it will be useful,
+GNU Wget is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
+along with Wget; if not, write to the Free Software
 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 #include <config.h>
@@ -24,6 +24,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
 #endif
+#include <assert.h>
 
 #ifdef WINDOWS
 # include <winsock.h>
@@ -31,7 +32,9 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 # include <sys/socket.h>
 # include <netdb.h>
 # include <netinet/in.h>
+#ifndef __BEOS__
 # include <arpa/inet.h>
+#endif
 #endif /* WINDOWS */
 
 #include <errno.h>
@@ -56,47 +59,145 @@ extern int errno;
 static int msock = -1;
 static struct sockaddr *addr;
 
+/* A kludge, but still better than passing the host name all the way
+   to connect_to_one.  */
+static const char *connection_host_name;
 
-/* Create an internet connection to HOSTNAME on PORT.  The created
-   socket will be stored to *SOCK.  */
-uerr_t
-make_connection (int *sock, char *hostname, unsigned short port)
+void
+set_connection_host_name (const char *host)
+{
+  if (host)
+    assert (connection_host_name == NULL);
+  else
+    assert (connection_host_name != NULL);
+
+  connection_host_name = host;
+}
+
+/* Connect to a remote host whose address has been resolved. */
+int
+connect_to_one (const unsigned char *addr, unsigned short port, int silent)
 {
   struct sockaddr_in sock_name;
-  /* struct hostent *hptr; */
-
-  /* Get internet address of the host.  We can do it either by calling
-     ngethostbyname, or by calling store_hostaddress, from host.c.
-     storehostaddress is better since it caches calls to
-     gethostbyname.  */
-#if 1
-  if (!store_hostaddress ((unsigned char *)&sock_name.sin_addr, hostname))
-    return HOSTERR;
-#else  /* never */
-  if (!(hptr = ngethostbyname (hostname)))
-    return HOSTERR;
-  /* Copy the address of the host to socket description.  */
-  memcpy (&sock_name.sin_addr, hptr->h_addr, hptr->h_length);
-#endif /* never */
+  int sock, save_errno;
 
   /* Set port and protocol */
   sock_name.sin_family = AF_INET;
   sock_name.sin_port = htons (port);
+  memcpy ((unsigned char *)&sock_name.sin_addr, addr, 4);
+
+  if (!silent)
+    {
+      char *pretty_addr = pretty_print_address (addr);
+      if (connection_host_name
+         && 0 != strcmp (connection_host_name, pretty_addr))
+       logprintf (LOG_VERBOSE, _("Connecting to %s[%s]:%hu... "),
+                  connection_host_name, pretty_addr, port);
+      else
+       logprintf (LOG_VERBOSE, _("Connecting to %s:%hu... "),
+                  pretty_addr, port);
+    }
 
   /* Make an internet socket, stream type.  */
-  if ((*sock = socket (AF_INET, SOCK_STREAM, 0)) == -1)
-    return CONSOCKERR;
+  sock = socket (AF_INET, SOCK_STREAM, 0);
+  if (sock < 0)
+    goto out;
+
+  if (opt.bind_address)
+    {
+      /* Bind the client side to the requested address. */
+      if (bind (sock, (struct sockaddr *)opt.bind_address,
+               sizeof (*opt.bind_address)))
+       {
+         close (sock);
+         sock = -1;
+         goto out;
+       }
+    }
 
   /* Connect the socket to the remote host.  */
-  if (connect (*sock, (struct sockaddr *) &sock_name, sizeof (sock_name)))
+  if (connect (sock, (struct sockaddr *)&sock_name, sizeof (sock_name)) < 0)
     {
-      if (errno == ECONNREFUSED)
-       return CONREFUSED;
-      else
-       return CONERROR;
+      close (sock);
+      sock = -1;
+      goto out;
+    }
+
+ out:
+  if (sock >= 0)
+    {
+      /* Success. */
+      if (!silent)
+       logprintf (LOG_VERBOSE, _("connected.\n"));
+      DEBUGP (("Created socket %d.\n", sock));
+    }
+  else
+    {
+      save_errno = errno;
+      if (!silent)
+       logprintf (LOG_VERBOSE, "failed: %s.\n", strerror (errno));
+      errno = save_errno;
+    }
+
+  return sock;
+}
+
+/* Connect to a remote host whose address has been resolved. */
+int
+connect_to_many (struct address_list *al, unsigned short port, int silent)
+{
+  int i, start, end;
+
+  address_list_get_bounds (al, &start, &end);
+  for (i = start; i < end; i++)
+    {
+      unsigned char addr[4];
+      int sock;
+      address_list_copy_one (al, i, addr);
+
+      sock = connect_to_one (addr, port, silent);
+      if (sock >= 0)
+       /* Success. */
+       return sock;
+
+      address_list_set_faulty (al, i);
+
+      /* The attempt to connect has failed.  Continue with the loop
+        and try next address. */
     }
-  DEBUGP (("Created fd %d.\n", *sock));
-  return NOCONERROR;
+
+  return -1;
+}
+
+int
+test_socket_open (int sock)
+{
+#ifdef HAVE_SELECT
+  fd_set check_set;
+  struct timeval to;
+
+  /* Check if we still have a valid (non-EOF) connection.  From Andrew
+   * Maholski's code in the Unix Socket FAQ.  */
+
+  FD_ZERO (&check_set);
+  FD_SET (sock, &check_set);
+
+  /* Wait one microsecond */
+  to.tv_sec = 0;
+  to.tv_usec = 1;
+
+  /* If we get a timeout, then that means still connected */
+  if (select (sock + 1, &check_set, NULL, NULL, &to) == 0)
+    {
+      /* Connection is valid (not EOF), so continue */
+      return 1;
+    }
+  else
+    return 0;
+#else
+  /* Without select, it's hard to know for sure. */
+  return 1;
+#endif
 }
 
 /* Bind the local port PORT.  This does all the necessary work, which
@@ -118,8 +219,15 @@ bindport (unsigned short *port)
   if (setsockopt (msock, SOL_SOCKET, SO_REUSEADDR,
                  (char *)&optval, sizeof (optval)) < 0)
     return CONSOCKERR;
-  srv.sin_family = AF_INET;
-  srv.sin_addr.s_addr = htonl (INADDR_ANY);
+
+  if (opt.bind_address == NULL)
+    {
+      srv.sin_family = AF_INET;
+      srv.sin_addr.s_addr = htonl (INADDR_ANY);
+    }
+  else
+    srv = *opt.bind_address;
+
   srv.sin_port = htons (*port);
   if (bind (msock, addr, sizeof (struct sockaddr_in)) < 0)
     {
@@ -130,8 +238,11 @@ bindport (unsigned short *port)
   DEBUGP (("Master socket fd %d bound.\n", msock));
   if (!*port)
     {
-      size_t addrlen = sizeof (struct sockaddr_in);
-      if (getsockname (msock, addr, (int *)&addrlen) < 0)
+      /* #### addrlen should be a 32-bit type, which int is not
+         guaranteed to be.  Oh, and don't try to make it a size_t,
+         because that can be 64-bit.  */
+      int addrlen = sizeof (struct sockaddr_in);
+      if (getsockname (msock, addr, &addrlen) < 0)
        {
          CLOSE (msock);
          msock = -1;
@@ -155,7 +266,7 @@ bindport (unsigned short *port)
 
    Returns 1 if FD is accessible, 0 for timeout and -1 for error in
    select().  */
-static int
+int
 select_fd (int fd, int maxtime, int writep)
 {
   fd_set fds, exceptfds;
@@ -214,7 +325,8 @@ conaddr (int fd)
   static unsigned char res[4];
   struct sockaddr_in mysrv;
   struct sockaddr *myaddr;
-  size_t addrlen = sizeof (mysrv);
+  int addrlen = sizeof (mysrv);        /* see bindport() for discussion of
+                                   using `int' here. */
 
   myaddr = (struct sockaddr *) (&mysrv);
   if (getsockname (fd, myaddr, (int *)&addrlen) < 0)