X-Git-Url: http://sjero.net/git/?a=blobdiff_plain;f=src%2Fconnect.c;h=29a8b6e0f09c12c3270fac8de09b96fe4aa21eb3;hb=f3d3a50a5697957befaf94cb44797234a68068c3;hp=28d2f6aa3395a5b37c904a0717286ed562490661;hpb=8196a09904b12ce5878fef6833a4091afafc9a24;p=wget diff --git a/src/connect.c b/src/connect.c index 28d2f6aa..29a8b6e0 100644 --- a/src/connect.c +++ b/src/connect.c @@ -1,5 +1,5 @@ /* Establishing and handling network connections. - Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc. + Copyright (C) 1995, 1996, 1997, 2001, 2002 Free Software Foundation, Inc. This file is part of GNU Wget. @@ -48,8 +48,9 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #endif /* HAVE_SYS_SELECT_H */ #include "wget.h" -#include "connect.h" +#include "utils.h" #include "host.h" +#include "connect.h" #ifndef errno extern int errno; @@ -59,6 +60,69 @@ extern int errno; static int msock = -1; static struct sockaddr *addr; +static ip_address bind_address; +static int bind_address_resolved; + +static void +resolve_bind_address (void) +{ + struct address_list *al; + + if (bind_address_resolved || opt.bind_address == NULL) + /* Nothing to do. */ + return; + + al = lookup_host (opt.bind_address, 1); + if (!al) + { + logprintf (LOG_NOTQUIET, + _("Unable to convert `%s' to a bind address. Reverting to ANY.\n"), + opt.bind_address); + return; + } + + address_list_copy_one (al, 0, &bind_address); + address_list_release (al); + bind_address_resolved = 1; +} + +struct cwt_context { + int fd; + const struct sockaddr *addr; + int addrlen; + int result; +}; + +static void +connect_with_timeout_callback (void *arg) +{ + struct cwt_context *ctx = (struct cwt_context *)arg; + ctx->result = connect (ctx->fd, ctx->addr, ctx->addrlen); +} + +/* Like connect, but specifies a timeout. If connecting takes longer + than TIMEOUT seconds, -1 is returned and errno is set to + ETIMEDOUT. */ + +static int +connect_with_timeout (int fd, const struct sockaddr *addr, int addrlen, + int timeout) +{ + struct cwt_context ctx; + ctx.fd = fd; + ctx.addr = addr; + ctx.addrlen = addrlen; + + if (run_with_timeout (timeout, connect_with_timeout_callback, &ctx)) + { + errno = ETIMEDOUT; + return -1; + } + if (ctx.result == -1 && errno == EINTR) + errno = ETIMEDOUT; + return ctx.result; +} + /* A kludge, but still better than passing the host name all the way to connect_to_one. */ static const char *connection_host_name; @@ -76,15 +140,13 @@ set_connection_host_name (const char *host) /* Connect to a remote host whose address has been resolved. */ int -connect_to_one (const unsigned char *addr, unsigned short port, int silent) +connect_to_one (ip_address *addr, unsigned short port, int silent) { - struct sockaddr_in sock_name; + wget_sockaddr sa; 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); + wget_sockaddr_set_address (&sa, ip_default_family, port, addr); if (!silent) { @@ -99,15 +161,17 @@ connect_to_one (const unsigned char *addr, unsigned short port, int silent) } /* Make an internet socket, stream type. */ - sock = socket (AF_INET, SOCK_STREAM, 0); + sock = socket (ip_default_family, SOCK_STREAM, 0); if (sock < 0) goto out; - if (opt.bind_address) + resolve_bind_address (); + if (bind_address_resolved) { /* Bind the client side to the requested address. */ - if (bind (sock, (struct sockaddr *)opt.bind_address, - sizeof (*opt.bind_address))) + wget_sockaddr bsa; + wget_sockaddr_set_address (&bsa, ip_default_family, 0, &bind_address); + if (bind (sock, &bsa.sa, sockaddr_len ())) { close (sock); sock = -1; @@ -116,7 +180,7 @@ connect_to_one (const unsigned char *addr, unsigned short port, int silent) } /* Connect the socket to the remote host. */ - if (connect (sock, (struct sockaddr *)&sock_name, sizeof (sock_name)) < 0) + if (connect_with_timeout (sock, &sa.sa, sockaddr_len (), opt.timeout) < 0) { close (sock); sock = -1; @@ -151,11 +215,11 @@ connect_to_many (struct address_list *al, unsigned short port, int silent) address_list_get_bounds (al, &start, &end); for (i = start; i < end; i++) { - unsigned char addr[4]; + ip_address addr; int sock; - address_list_copy_one (al, i, addr); + address_list_copy_one (al, i, &addr); - sock = connect_to_one (addr, port, silent); + sock = connect_to_one (&addr, port, silent); if (sock >= 0) /* Success. */ return sock; @@ -207,29 +271,24 @@ test_socket_open (int sock) internal variable MPORT is set to the value of the ensuing master socket. Call acceptport() to block for and accept a connection. */ uerr_t -bindport (unsigned short *port) +bindport (unsigned short *port, int family) { int optval = 1; - static struct sockaddr_in srv; + wget_sockaddr srv; + memset (&srv, 0, sizeof (wget_sockaddr)); msock = -1; - addr = (struct sockaddr *) &srv; - if ((msock = socket (AF_INET, SOCK_STREAM, 0)) < 0) + + if ((msock = socket (family, SOCK_STREAM, 0)) < 0) return CONSOCKERR; if (setsockopt (msock, SOL_SOCKET, SO_REUSEADDR, (char *)&optval, sizeof (optval)) < 0) return CONSOCKERR; - 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) + resolve_bind_address (); + wget_sockaddr_set_address (&srv, ip_default_family, htons (*port), + bind_address_resolved ? &bind_address : NULL); + if (bind (msock, &srv.sa, sockaddr_len ()) < 0) { CLOSE (msock); msock = -1; @@ -241,14 +300,15 @@ bindport (unsigned short *port) /* #### 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) + int sa_len = sockaddr_len (); + if (getsockname (msock, &srv.sa, &sa_len) < 0) { CLOSE (msock); msock = -1; return CONPORTERR; } - *port = ntohs (srv.sin_port); + *port = wget_sockaddr_get_port (&srv); + DEBUGP (("using port %i.\n", *port)); } if (listen (msock, 1) < 0) { @@ -292,7 +352,7 @@ select_fd (int fd, int maxtime, int writep) uerr_t acceptport (int *sock) { - int addrlen = sizeof (struct sockaddr_in); + int addrlen = sockaddr_len (); #ifdef HAVE_SELECT if (select_fd (msock, opt.timeout, 0) <= 0) @@ -317,22 +377,33 @@ closeport (int sock) msock = -1; } -/* Return the local IP address associated with the connection on FD. - It is returned in a static buffer. */ -unsigned char * -conaddr (int fd) +/* Return the local IP address associated with the connection on FD. */ + +int +conaddr (int fd, ip_address *ip) { - static unsigned char res[4]; - struct sockaddr_in mysrv; - struct sockaddr *myaddr; - int addrlen = sizeof (mysrv); /* see bindport() for discussion of - using `int' here. */ - - myaddr = (struct sockaddr *) (&mysrv); - if (getsockname (fd, myaddr, (int *)&addrlen) < 0) - return NULL; - memcpy (res, &mysrv.sin_addr, 4); - return res; + wget_sockaddr mysrv; + + /* see bindport() for discussion of using `int' here. */ + int addrlen = sizeof (mysrv); + + if (getsockname (fd, &mysrv.sa, (int *)&addrlen) < 0) + return 0; + + switch (mysrv.sa.sa_family) + { +#ifdef INET6 + case AF_INET6: + memcpy (ip, &mysrv.sin6.sin6_addr, 16); + return 1; +#endif + case AF_INET: + map_ipv4_to_ip ((ip4_address *)&mysrv.sin.sin_addr, ip); + return 1; + default: + abort (); + } + return 0; } /* Read at most LEN bytes from FD, storing them to BUF. This is