From add61a2d9c99450e709631a9ef20d8bb521dc01e Mon Sep 17 00:00:00 2001 From: hniksic Date: Thu, 30 Oct 2003 16:18:08 -0800 Subject: [PATCH] [svn] Networking improvements: get rid of the MSOCK global variable, move the sockaddr handling to connect.c, make sure Wget refreshes the DNS lookup after it becomes stale. --- src/ChangeLog | 33 +++++ src/connect.c | 334 ++++++++++++++++++++++++++++++------------------ src/connect.h | 25 +++- src/ftp-basic.c | 60 ++++----- src/ftp.c | 109 +++++++++------- src/ftp.h | 12 +- src/host.c | 266 +++++++------------------------------- src/host.h | 20 +-- src/http.c | 11 +- src/sysdep.h | 15 ++- 10 files changed, 424 insertions(+), 461 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 3c80d28a..613e4252 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,36 @@ +2003-10-31 Hrvoje Niksic + + * sysdep.h (CLOSE): Don't call close on file descriptors less than + 0, i.e. on uncreated sockets. + + * connect.c (resolve_bind_address): Work on struct sockaddr + directly. + (connect_to_host): Replacement for connect_to_many. Resolve HOST + and connect to any of its addresses. If we can't connect and the + host name lookup was cached, try to resolve it again. This should + fix problems with hosts behind dynamic DNS. Updated all callers. + (connect_to_ip): Replacement for connect_to_one. Removed SILENT; + added the argument PRINT instead. Updated all callers. + (set_connection_host_name): Removed. + + * host.c (address_list_address_at): New function instead of + address_list_copy_one. It returns a pointer to ip_address *, so + it's not necessary to copy the data. + (address_list_cached_p): New function. + (forget_host_lookup): Ditto. + + * connect.c: Got rid of the MSOCK global variable. Made bindport + return the local socket it creates. Added a new argument to + acceptport, the socket to call accept on. Updated callers. + (closeport): Removed. + + * connect.c: Moved the sockaddr code from host.c to this file, + because most of that stuff is used for connecting, and has nothing + to do with host names anyway. + (sockaddr_set_data, sockaddr_get_data): New functions, replace the + old sockaddr_set_address, sockaddr_set_port, sockaddr_get_address, + and sockaddr_get_port. + 2003-10-30 Hrvoje Niksic * sysdep.h: Use `S >= 8' rather than `S == 8' when looking for diff --git a/src/connect.c b/src/connect.c index 7e52b691..89a85f2f 100644 --- a/src/connect.c +++ b/src/connect.c @@ -6,7 +6,7 @@ This file is part of GNU Wget. 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. + (at your option) any later version. GNU Wget is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -65,48 +65,143 @@ so, delete this exception statement from your version. */ extern int errno; #endif -/* Variables shared by bindport and acceptport: */ -static int msock = -1; -/*static struct sockaddr *addr;*/ - -static int -resolve_bind_address (int flags, ip_address *addr) + +/** + * sockaddr_set_data + * + * This function takes a sockaddr struct and fills in the protocol + * type, the port number and the address. If ENABLE_IPV6 is defined, + * SA should really point to struct sockaddr_storage; otherwise, it + * should point to struct sockaddr_in. + * + * Input: + * struct sockaddr* The space to be filled + * const ip_address The IP address + * int The port + * + * Return: + * - Only modifies 1st parameter. + */ +static void +sockaddr_set_data (struct sockaddr *sa, const ip_address *addr, int port) { - struct address_list *al = NULL; - int resolved = 0; + if (addr->type == IPV4_ADDRESS) + { + struct sockaddr_in *sin = (struct sockaddr_in *)sa; + sin->sin_family = AF_INET; + sin->sin_port = htons (port); + if (addr == NULL) + sin->sin_addr.s_addr = INADDR_ANY; + else + sin->sin_addr = ADDRESS_IPV4_IN_ADDR (addr); + } +#ifdef ENABLE_IPV6 + else if (addr->type == IPV6_ADDRESS) + { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; + sin6->sin6_family = AF_INET6; + sin6->sin6_port = htons (port); + /* #### How can ADDR be NULL? We have dereferenced it above by + accessing addr->type! */ + if (addr == NULL) + { + sin6->sin6_addr = in6addr_any; + /* #### Should we set the scope_id here? */ + } + else + { + sin6->sin6_addr = ADDRESS_IPV6_IN6_ADDR (addr); +#ifdef HAVE_SOCKADDR_IN6_SCOPE_ID + sin6->sin6_scope_id = ADDRESS_IPV6_SCOPE (addr); +#endif + } + } +#endif /* ENABLE_IPV6 */ + else + abort (); +} + +/* Get the data of SA, specifically the IP address and the port. If + you're not interested in one or the other information, pass NULL as + the pointer. */ - if (opt.bind_address != NULL) +void +sockaddr_get_data (const struct sockaddr *sa, ip_address *ip, int *port) +{ + if (sa->sa_family == AF_INET) + { + struct sockaddr_in *sin = (struct sockaddr_in *)sa; + if (ip) + { + ip->type = IPV4_ADDRESS; + ADDRESS_IPV4_IN_ADDR (ip) = sin->sin_addr; + } + if (port) + *port = ntohs (sin->sin_port); + } +#ifdef ENABLE_IPV6 + else if (sa->sa_family == AF_INET6) { - al = lookup_host (opt.bind_address, flags | LH_SILENT | LH_PASSIVE); - if (al == NULL) - { - logprintf (LOG_NOTQUIET, - _("Unable to convert `%s' to a bind address. Reverting to ANY.\n"), - opt.bind_address); + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; + if (ip) + { + ip->type = IPV6_ADDRESS; + ADDRESS_IPV6_IN6_ADDR (ip) = sin6->sin6_addr; +#ifdef HAVE_SOCKADDR_IN6_SCOPE_ID + ADDRESS_IPV6_SCOPE (ip) = sin6->sin6_scope_id; +#endif } - else - resolved = 1; + if (port) + *port = ntohs (sin6->sin6_port); } +#endif + else + abort (); +} - if (al == NULL) +/* Return the size of the sockaddr structure depending on its + family. */ + +static socklen_t +sockaddr_size (const struct sockaddr *sa) +{ + switch (sa->sa_family) { - /* #### Is there really a need for this? Shouldn't we simply - return 0 and have the caller use sockaddr_set_address to - specify INADDR_ANY/in6addr_any? */ - const char *unspecified_address = "0.0.0.0"; + case AF_INET: + return sizeof (struct sockaddr_in); #ifdef ENABLE_IPV6 - if (flags & BIND_ON_IPV6_ONLY) - unspecified_address = "::"; + case AF_INET6: + return sizeof (struct sockaddr_in6); #endif - al = lookup_host (unspecified_address, LH_SILENT | LH_PASSIVE); + default: + abort (); + return 0; /* so the compiler shuts up. */ } +} + +static int +resolve_bind_address (const char *host, struct sockaddr *sa, int flags) +{ + struct address_list *al; - assert (al != NULL); + /* #### Shouldn't we do this only once? opt.bind_address won't + change during a Wget run! */ - address_list_copy_one (al, 0, addr); - address_list_release (al); + al = lookup_host (host, flags | LH_SILENT | LH_PASSIVE); + if (al == NULL) + { + logprintf (LOG_NOTQUIET, + _("Unable to convert `%s' to a bind address. Reverting to ANY.\n"), + opt.bind_address); + return 0; + } - return resolved; + /* Pick the first address in the list and use it as bind address. + Perhaps we should try multiple addresses, but I don't think + that's necessary in practice. */ + sockaddr_set_data (sa, address_list_address_at (al, 0), 0); + address_list_release (al); + return 1; } struct cwt_context { @@ -146,76 +241,61 @@ connect_with_timeout (int fd, const struct sockaddr *addr, socklen_t addrlen, 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; - -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 endpoint whose IP address is known. */ -/* Connect to a remote host whose address has been resolved. */ int -connect_to_one (ip_address *addr, unsigned short port, int silent) +connect_to_ip (const ip_address *ip, int port, const char *print) { struct sockaddr_storage ss; struct sockaddr *sa = (struct sockaddr *)&ss; int sock, save_errno; - /* Set port and protocol */ - sockaddr_set_address (sa, port, addr); - - if (!silent) + /* If PRINT is non-NULL, print the "Connecting to..." line, with + PRINT being the host name we're connecting to. */ + if (print) { - const 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); + const char *txt_addr = pretty_print_address (ip); + if (print && 0 != strcmp (print, txt_addr)) + logprintf (LOG_VERBOSE, + _("Connecting to %s{%s}:%d... "), print, txt_addr, port); else - logprintf (LOG_VERBOSE, _("Connecting to %s:%hu... "), - pretty_addr, port); + logprintf (LOG_VERBOSE, _("Connecting to %s:%d... "), txt_addr, port); } + /* Store the sockaddr info to SA. */ + sockaddr_set_data (sa, ip, port); + /* Create the socket of the family appropriate for the address. */ sock = socket (sa->sa_family, SOCK_STREAM, 0); if (sock < 0) goto out; /* For very small rate limits, set the buffer size (and hence, - hopefully, the size of the kernel window) to the size of the - limit. That way we don't sleep for more than 1s between network - reads. */ + hopefully, the kernel's TCP window size) to the per-second limit. + That way we should never have to sleep for more than 1s between + network reads. */ if (opt.limit_rate && opt.limit_rate < 8192) { int bufsize = opt.limit_rate; if (bufsize < 512) - bufsize = 512; + bufsize = 512; /* avoid pathologically small values */ #ifdef SO_RCVBUF setsockopt (sock, SOL_SOCKET, SO_RCVBUF, - (char *)&bufsize, sizeof (bufsize)); + (void *)&bufsize, (socklen_t)sizeof (bufsize)); #endif - /* When we add opt.limit_rate support for writing, as with - `--post-file', also set SO_SNDBUF here. */ + /* When we add limit_rate support for writing, which is useful + for POST, we should also set SO_SNDBUF here. */ } if (opt.bind_address) { - /* Bind the client side to the requested address. */ - ip_address bind_address; - if (resolve_bind_address (0, &bind_address)) - { - struct sockaddr_storage bss; - struct sockaddr *bsa = (struct sockaddr *)&bss; - sockaddr_set_address (bsa, 0, &bind_address); - if (bind (sock, bsa, sockaddr_len (bsa))) + /* Bind the client side of the socket to the requested + address. */ + struct sockaddr_storage bind_ss; + struct sockaddr *bind_sa = (struct sockaddr *)&bind_ss; + if (resolve_bind_address (opt.bind_address, bind_sa, 0)) + { + if (bind (sock, bind_sa, sockaddr_size (bind_sa)) < 0) { CLOSE (sock); sock = -1; @@ -224,8 +304,8 @@ connect_to_one (ip_address *addr, unsigned short port, int silent) } } - /* Connect the socket to the remote host. */ - if (connect_with_timeout (sock, sa, sockaddr_len (sa), + /* Connect the socket to the remote endpoint. */ + if (connect_with_timeout (sock, sa, sockaddr_size (sa), opt.connect_timeout) < 0) { CLOSE (sock); @@ -237,14 +317,14 @@ connect_to_one (ip_address *addr, unsigned short port, int silent) if (sock >= 0) { /* Success. */ - if (!silent) + if (print) logprintf (LOG_VERBOSE, _("connected.\n")); DEBUGP (("Created socket %d.\n", sock)); } else { save_errno = errno; - if (!silent) + if (print) logprintf (LOG_VERBOSE, "failed: %s.\n", strerror (errno)); errno = save_errno; } @@ -252,31 +332,47 @@ connect_to_one (ip_address *addr, unsigned short port, int silent) return sock; } -/* Connect to a remote host whose address has been resolved. */ +/* Connect to a remote endpoint specified by host name. */ + int -connect_to_many (struct address_list *al, unsigned short port, int silent) +connect_to_host (const char *host, int port) { int i, start, end; + struct address_list *al; + int sock = -1; + + again: + al = lookup_host (host, 0); + if (!al) + return E_HOST; address_list_get_bounds (al, &start, &end); for (i = start; i < end; i++) { - ip_address addr; - int sock; - address_list_copy_one (al, i, &addr); - - sock = connect_to_one (&addr, port, silent); + const ip_address *ip = address_list_address_at (al, i); + sock = connect_to_ip (ip, port, host); if (sock >= 0) /* Success. */ - return sock; + break; address_list_set_faulty (al, i); /* The attempt to connect has failed. Continue with the loop and try next address. */ } + address_list_release (al); + + if (sock < 0 && address_list_cached_p (al)) + { + /* We were unable to connect to any address in a list we've + obtained from cache. There is a possibility that the host is + under dynamic DNS and has changed its address. Resolve it + again. */ + forget_host_lookup (host); + goto again; + } - return -1; + return sock; } int @@ -310,37 +406,36 @@ test_socket_open (int sock) #endif } -/* Bind the local port PORT. This does all the necessary work, which - is creating a socket, setting SO_REUSEADDR option on it, then - calling bind() and listen(). If *PORT is 0, a random port is - chosen by the system, and its value is stored to *PORT. The - internal variable MPORT is set to the value of the ensuing master - socket. Call acceptport() to block for and accept a connection. */ +/* Create a socket and bind it to PORT locally. Calling accept() on + such a socket waits for and accepts incoming TCP connections. The + resulting socket is stored to LOCAL_SOCK. */ uerr_t -bindport (const ip_address *bind_address, unsigned short *port) +bindport (const ip_address *bind_address, int *port, int *local_sock) { + int msock; int family = AF_INET; int optval; struct sockaddr_storage ss; struct sockaddr *sa = (struct sockaddr *)&ss; memset (&ss, 0, sizeof (ss)); - msock = -1; - #ifdef ENABLE_IPV6 if (bind_address->type == IPV6_ADDRESS) family = AF_INET6; #endif - + if ((msock = socket (family, SOCK_STREAM, 0)) < 0) return CONSOCKERR; #ifdef SO_REUSEADDR optval = 1; if (setsockopt (msock, SOL_SOCKET, SO_REUSEADDR, - (char *)&optval, sizeof (optval)) < 0) - return CONSOCKERR; + (void *)&optval, (socklen_t)sizeof (optval)) < 0) + { + CLOSE (msock); + return CONSOCKERR; + } #endif #ifdef ENABLE_IPV6 @@ -350,38 +445,36 @@ bindport (const ip_address *bind_address, unsigned short *port) optval = 1; /* if setsockopt fails, go on anyway */ setsockopt (msock, IPPROTO_IPV6, IPV6_V6ONLY, - (char *)&optval, sizeof (optval)); + (void *)&optval, (socklen_t)sizeof (optval)); } # endif #endif - - sockaddr_set_address (sa, htons (*port), bind_address); - if (bind (msock, sa, sockaddr_len (sa)) < 0) + + sockaddr_set_data (sa, bind_address, *port); + if (bind (msock, sa, sockaddr_size (sa)) < 0) { CLOSE (msock); - msock = -1; return BINDERR; } - DEBUGP (("Master socket fd %d bound.\n", msock)); + DEBUGP (("Local socket fd %d bound.\n", msock)); if (!*port) { - socklen_t sa_len = sockaddr_len (sa); + socklen_t sa_len = sockaddr_size (sa); if (getsockname (msock, sa, &sa_len) < 0) { CLOSE (msock); - msock = -1; return CONPORTERR; } - *port = sockaddr_get_port (sa); + sockaddr_get_data (sa, NULL, port); DEBUGP (("binding to address %s using port %i.\n", pretty_print_address (bind_address), *port)); } if (listen (msock, 1) < 0) { CLOSE (msock); - msock = -1; return LISTENERR; } + *local_sock = msock; return BINDOK; } @@ -420,41 +513,28 @@ select_fd (int fd, double maxtime, int writep) } #endif /* HAVE_SELECT */ -/* Call accept() on MSOCK and store the result to *SOCK. This assumes - that bindport() has been used to initialize MSOCK to a correct - value. It blocks the caller until a connection is established. If - no connection is established for OPT.CONNECT_TIMEOUT seconds, the +/* Accept a connection on LOCAL_SOCK, and store the new socket to + *SOCK. It blocks the caller until a connection is established. If + no connection is established for opt.connect_timeout seconds, the function exits with an error status. */ + uerr_t -acceptport (int *sock) +acceptport (int local_sock, int *sock) { struct sockaddr_storage ss; struct sockaddr *sa = (struct sockaddr *)&ss; socklen_t addrlen = sizeof (ss); #ifdef HAVE_SELECT - if (select_fd (msock, opt.connect_timeout, 0) <= 0) + if (select_fd (local_sock, opt.connect_timeout, 0) <= 0) return ACCEPTERR; #endif - if ((*sock = accept (msock, sa, &addrlen)) < 0) + if ((*sock = accept (local_sock, sa, &addrlen)) < 0) return ACCEPTERR; DEBUGP (("Created socket fd %d.\n", *sock)); return ACCEPTOK; } -/* Close SOCK, as well as the most recently remembered MSOCK, created - via bindport(). If SOCK is -1, close MSOCK only. */ -void -closeport (int sock) -{ - /*shutdown (sock, 2);*/ - if (sock != -1) - CLOSE (sock); - if (msock != -1) - CLOSE (msock); - msock = -1; -} - /* Return the local IP address associated with the connection on FD. */ int diff --git a/src/connect.h b/src/connect.h index a020bf25..ab161c0b 100644 --- a/src/connect.h +++ b/src/connect.h @@ -6,7 +6,7 @@ This file is part of GNU Wget. 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. + (at your option) any later version. GNU Wget is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -32,21 +32,32 @@ so, delete this exception statement from your version. */ #include "host.h" /* for definition of ip_address */ +/* Returned by connect_to_host when host name cannot be resolved. */ +enum { + E_HOST = -100 +}; + /* bindport flags */ #define BIND_ON_IPV4_ONLY LH_IPV4_ONLY #define BIND_ON_IPV6_ONLY LH_IPV6_ONLY +#ifndef ENABLE_IPV6 +# ifndef HAVE_SOCKADDR_STORAGE +# define sockaddr_storage sockaddr_in +# endif +#endif /* ENABLE_IPV6 */ + /* Function declarations */ -int connect_to_one PARAMS ((ip_address *, unsigned short, int)); -int connect_to_many PARAMS ((struct address_list *, unsigned short, int)); -void set_connection_host_name PARAMS ((const char *)); +int connect_to_ip PARAMS ((const ip_address *, int, const char *)); +int connect_to_host PARAMS ((const char *, int)); + +void sockaddr_get_data PARAMS ((const struct sockaddr *, ip_address *, int *)); int test_socket_open PARAMS ((int)); int select_fd PARAMS ((int, double, int)); -uerr_t bindport PARAMS ((const ip_address *, unsigned short *)); -uerr_t acceptport PARAMS ((int *)); -void closeport PARAMS ((int)); +uerr_t bindport PARAMS ((const ip_address *, int *, int *)); +uerr_t acceptport PARAMS ((int, int *)); int conaddr PARAMS ((int, ip_address *)); int iread PARAMS ((int, char *, int)); diff --git a/src/ftp-basic.c b/src/ftp-basic.c index 84095793..8d763ebb 100644 --- a/src/ftp-basic.c +++ b/src/ftp-basic.c @@ -254,7 +254,7 @@ ftp_login (struct rbuf *rbuf, const char *acc, const char *pass) } static void -ip_address_to_port_repr (const ip_address *addr, unsigned short port, char *buf, +ip_address_to_port_repr (const ip_address *addr, int port, char *buf, size_t buflen) { unsigned char *ptr; @@ -267,7 +267,7 @@ ip_address_to_port_repr (const ip_address *addr, unsigned short port, char *buf, ptr = ADDRESS_IPV4_DATA (addr); snprintf (buf, buflen, "%d,%d,%d,%d,%d,%d", ptr[0], ptr[1], - ptr[2], ptr[3], (unsigned) (port & 0xff00) >> 8, port & 0xff); + ptr[2], ptr[3], (port & 0xff00) >> 8, port & 0xff); buf[buflen - 1] = '\0'; } @@ -275,13 +275,13 @@ ip_address_to_port_repr (const ip_address *addr, unsigned short port, char *buf, server. Use acceptport after RETR, to get the socket of data connection. */ uerr_t -ftp_port (struct rbuf *rbuf) +ftp_port (struct rbuf *rbuf, int *local_sock) { uerr_t err; char *request, *respline; ip_address addr; int nwritten; - unsigned short port; + int port; /* Must contain the argument of PORT (of the form a,b,c,d,e,f). */ char bytes[6 * 4 + 1]; @@ -298,7 +298,7 @@ ftp_port (struct rbuf *rbuf) port = 0; /* Bind the port. */ - err = bindport (&addr, &port); + err = bindport (&addr, &port, local_sock); if (err != BINDOK) return err; @@ -311,7 +311,7 @@ ftp_port (struct rbuf *rbuf) if (nwritten < 0) { xfree (request); - closeport (-1); + CLOSE (*local_sock); return WRITEFAILED; } xfree (request); @@ -321,13 +321,13 @@ ftp_port (struct rbuf *rbuf) if (err != FTPOK) { xfree (respline); - closeport (-1); + CLOSE (*local_sock); return err; } if (*respline != '2') { xfree (respline); - closeport (-1); + CLOSE (*local_sock); return FTPPORTERR; } xfree (respline); @@ -336,7 +336,7 @@ ftp_port (struct rbuf *rbuf) #ifdef ENABLE_IPV6 static void -ip_address_to_lprt_repr (const ip_address *addr, unsigned short port, char *buf, +ip_address_to_lprt_repr (const ip_address *addr, int port, char *buf, size_t buflen) { unsigned char *ptr; @@ -354,7 +354,7 @@ ip_address_to_lprt_repr (const ip_address *addr, unsigned short port, char *buf, ptr = ADDRESS_IPV4_DATA (addr); snprintf (buf, buflen, "%d,%d,%d,%d,%d,%d,%d,%d,%d", 4, 4, ptr[0], ptr[1], ptr[2], ptr[3], 2, - (unsigned) (port & 0xff00) >> 8, port & 0xff); + (port & 0xff00) >> 8, port & 0xff); buf[buflen - 1] = '\0'; break; case IPV6_ADDRESS: @@ -362,7 +362,7 @@ ip_address_to_lprt_repr (const ip_address *addr, unsigned short port, char *buf, snprintf (buf, buflen, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", 6, 16, ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7], ptr[8], ptr[9], ptr[10], ptr[11], ptr[12], ptr[13], ptr[14], ptr[15], 2, - (unsigned) (port & 0xff00) >> 8, port & 0xff); + (port & 0xff00) >> 8, port & 0xff); buf[buflen - 1] = '\0'; break; } @@ -372,13 +372,13 @@ ip_address_to_lprt_repr (const ip_address *addr, unsigned short port, char *buf, server. Use acceptport after RETR, to get the socket of data connection. */ uerr_t -ftp_lprt (struct rbuf *rbuf) +ftp_lprt (struct rbuf *rbuf, int *local_sock) { uerr_t err; char *request, *respline; ip_address addr; int nwritten; - unsigned short port; + int port; /* Must contain the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */ char bytes[21 * 4 + 1]; @@ -395,7 +395,7 @@ ftp_lprt (struct rbuf *rbuf) port = 0; /* Bind the port. */ - err = bindport (&addr, &port); + err = bindport (&addr, &port, local_sock); if (err != BINDOK) return err; @@ -408,7 +408,7 @@ ftp_lprt (struct rbuf *rbuf) if (nwritten < 0) { xfree (request); - closeport (-1); + CLOSE (*local_sock); return WRITEFAILED; } xfree (request); @@ -417,13 +417,13 @@ ftp_lprt (struct rbuf *rbuf) if (err != FTPOK) { xfree (respline); - closeport (-1); + CLOSE (*local_sock); return err; } if (*respline != '2') { xfree (respline); - closeport (-1); + CLOSE (*local_sock); return FTPPORTERR; } xfree (respline); @@ -431,7 +431,7 @@ ftp_lprt (struct rbuf *rbuf) } static void -ip_address_to_eprt_repr (const ip_address *addr, unsigned short port, char *buf, +ip_address_to_eprt_repr (const ip_address *addr, int port, char *buf, size_t buflen) { int afnum; @@ -454,13 +454,13 @@ ip_address_to_eprt_repr (const ip_address *addr, unsigned short port, char *buf, server. Use acceptport after RETR, to get the socket of data connection. */ uerr_t -ftp_eprt (struct rbuf *rbuf) +ftp_eprt (struct rbuf *rbuf, int *local_sock) { uerr_t err; char *request, *respline; ip_address addr; int nwritten; - unsigned short port; + int port; /* Must contain the argument of EPRT (of the form |af|addr|port|). * 4 chars for the | separators, ENABLE_IPV6_ADDRSTRLEN chars for addr * 1 char for af (1-2) and 5 chars for port (0-65535) */ @@ -479,7 +479,7 @@ ftp_eprt (struct rbuf *rbuf) port = 0; /* Bind the port. */ - err = bindport (&addr, &port); + err = bindport (&addr, &port, local_sock); if (err != BINDOK) return err; @@ -492,7 +492,7 @@ ftp_eprt (struct rbuf *rbuf) if (nwritten < 0) { xfree (request); - closeport (-1); + CLOSE (*local_sock); return WRITEFAILED; } xfree (request); @@ -501,13 +501,13 @@ ftp_eprt (struct rbuf *rbuf) if (err != FTPOK) { xfree (respline); - closeport (-1); + CLOSE (*local_sock); return err; } if (*respline != '2') { xfree (respline); - closeport (-1); + CLOSE (*local_sock); return FTPPORTERR; } xfree (respline); @@ -519,7 +519,7 @@ ftp_eprt (struct rbuf *rbuf) transfer. Reads the response from server and parses it. Reads the host and port addresses and returns them. */ uerr_t -ftp_pasv (struct rbuf *rbuf, ip_address *addr, unsigned short *port) +ftp_pasv (struct rbuf *rbuf, ip_address *addr, int *port) { char *request, *respline, *s; int nwritten, i; @@ -588,7 +588,7 @@ ftp_pasv (struct rbuf *rbuf, ip_address *addr, unsigned short *port) transfer. Reads the response from server and parses it. Reads the host and port addresses and returns them. */ uerr_t -ftp_lpsv (struct rbuf *rbuf, ip_address *addr, unsigned short *port) +ftp_lpsv (struct rbuf *rbuf, ip_address *addr, int *port) { char *request, *respline, *s; int nwritten, i, af, addrlen, portlen; @@ -754,19 +754,19 @@ ftp_lpsv (struct rbuf *rbuf, ip_address *addr, unsigned short *port) transfer. Reads the response from server and parses it. Reads the host and port addresses and returns them. */ uerr_t -ftp_epsv (struct rbuf *rbuf, ip_address *addr, unsigned short *port) +ftp_epsv (struct rbuf *rbuf, ip_address *ip, int *port) { char *request, *respline, *start, delim, *s; int nwritten, i; uerr_t err; - unsigned short tport; + int tport; socklen_t addrlen; struct sockaddr_storage ss; struct sockaddr *sa = (struct sockaddr *)&ss; assert (rbuf != NULL); assert (rbuf_initialized_p(rbuf)); - assert (addr != NULL); + assert (ip != NULL); assert (port != NULL); addrlen = sizeof (ss); @@ -776,7 +776,7 @@ ftp_epsv (struct rbuf *rbuf, ip_address *addr, unsigned short *port) assert (sa->sa_family == AF_INET || sa->sa_family == AF_INET6); - sockaddr_get_address (sa, NULL, addr); + sockaddr_get_data (sa, ip, NULL); /* Form the request. */ /* EPSV 1 means that we ask for IPv4 and EPSV 2 means that we ask for IPv6. */ diff --git a/src/ftp.c b/src/ftp.c index 8c3b4869..69065490 100644 --- a/src/ftp.c +++ b/src/ftp.c @@ -143,7 +143,7 @@ getfamily (int fd) * It is merely a wrapper around ftp_epsv, ftp_lpsv and ftp_pasv. */ static uerr_t -ftp_do_pasv (struct rbuf *rbuf, ip_address *addr, unsigned short *port) +ftp_do_pasv (struct rbuf *rbuf, ip_address *addr, int *port) { uerr_t err; int family; @@ -183,7 +183,7 @@ ftp_do_pasv (struct rbuf *rbuf, ip_address *addr, unsigned short *port) * It is merely a wrapper around ftp_eprt, ftp_lprt and ftp_port. */ static uerr_t -ftp_do_port (struct rbuf *rbuf) +ftp_do_port (struct rbuf *rbuf, int *local_sock) { uerr_t err; int family; @@ -201,28 +201,42 @@ ftp_do_port (struct rbuf *rbuf) { if (!opt.server_response) logputs (LOG_VERBOSE, "==> EPRT ... "); - err = ftp_eprt (rbuf); + err = ftp_eprt (rbuf, local_sock); /* If EPRT is not supported try LPRT */ if (err == FTPPORTERR) { if (!opt.server_response) logputs (LOG_VERBOSE, "==> LPRT ... "); - err = ftp_lprt (rbuf); + err = ftp_lprt (rbuf, local_sock); } } else { if (!opt.server_response) logputs (LOG_VERBOSE, "==> PORT ... "); - err = ftp_port (rbuf); + err = ftp_port (rbuf, local_sock); } return err; } #else -#define ftp_do_pasv ftp_pasv -#define ftp_do_port ftp_port + +static uerr_t +ftp_do_pasv (struct rbuf *rbuf, ip_address *addr, int *port) +{ + if (!opt.server_response) + logputs (LOG_VERBOSE, "==> PASV ... "); + return ftp_pasv (rbuf, addr, port); +} + +static uerr_t +ftp_do_port (struct rbuf *rbuf, int *local_sock) +{ + if (!opt.server_response) + logputs (LOG_VERBOSE, "==> PORT ... "); + return ftp_port (rbuf, local_sock); +} #endif /* Retrieves a file with denoted parameters through opening an FTP @@ -231,7 +245,7 @@ ftp_do_port (struct rbuf *rbuf) static uerr_t getftp (struct url *u, long *len, long restval, ccon *con) { - int csock, dtsock, res; + int csock, dtsock, local_sock, res; uerr_t err; FILE *fp; char *user, *passwd, *respline; @@ -258,6 +272,7 @@ getftp (struct url *u, long *len, long restval, ccon *con) assert (user && passwd); dtsock = -1; + local_sock = -1; con->dltime = 0; if (!(cmd & DO_LOGIN)) @@ -265,8 +280,6 @@ getftp (struct url *u, long *len, long restval, ccon *con) else /* cmd & DO_LOGIN */ { char type_char; - struct address_list *al; - char *host = con->proxy ? con->proxy->host : u->host; int port = con->proxy ? con->proxy->port : u->port; char *logname = user; @@ -282,15 +295,10 @@ getftp (struct url *u, long *len, long restval, ccon *con) /* First: Establish the control connection. */ - al = lookup_host (host, 0); - if (!al) + csock = connect_to_host (host, port); + if (csock == E_HOST) return HOSTERR; - set_connection_host_name (host); - csock = connect_to_many (al, port, 0); - set_connection_host_name (NULL); - address_list_release (al); - - if (csock < 0) + else if (csock < 0) return CONNECT_ERROR (errno); if (cmd & LEAVE_PENDING) @@ -642,10 +650,8 @@ Error in server response, closing control connection.\n")); { if (opt.ftp_pasv > 0) { - ip_address passive_addr; - unsigned short passive_port; - if (!opt.server_response) - logputs (LOG_VERBOSE, "==> PASV ... "); + ip_address passive_addr; + int passive_port; err = ftp_do_pasv (&con->rbuf, &passive_addr, &passive_port); /* FTPRERR, WRITEFAILED, FTPNOPASV, FTPINVPASV */ switch (err) @@ -686,7 +692,7 @@ Error in server response, closing control connection.\n")); DEBUGP (("trying to connect to %s port %d\n", pretty_print_address (&passive_addr), passive_port)); - dtsock = connect_to_one (&passive_addr, passive_port, 1); + dtsock = connect_to_ip (&passive_addr, passive_port, NULL); if (dtsock < 0) { int save_errno = errno; @@ -706,9 +712,7 @@ Error in server response, closing control connection.\n")); if (!pasv_mode_open) /* Try to use a port command if PASV failed */ { - if (!opt.server_response) - logputs (LOG_VERBOSE, "==> PORT ... "); - err = ftp_do_port (&con->rbuf); + err = ftp_do_port (&con->rbuf, &local_sock); /* FTPRERR, WRITEFAILED, bindport (CONSOCKERR, CONPORTERR, BINDERR, LISTENERR), HOSTERR, FTPPORTERR */ switch (err) @@ -718,7 +722,8 @@ Error in server response, closing control connection.\n")); logputs (LOG_NOTQUIET, _("\ Error in server response, closing control connection.\n")); CLOSE (csock); - closeport (dtsock); + CLOSE (dtsock); + CLOSE (local_sock); rbuf_uninitialize (&con->rbuf); return err; break; @@ -727,7 +732,8 @@ Error in server response, closing control connection.\n")); logputs (LOG_NOTQUIET, _("Write failed, closing control connection.\n")); CLOSE (csock); - closeport (dtsock); + CLOSE (dtsock); + CLOSE (local_sock); rbuf_uninitialize (&con->rbuf); return err; break; @@ -735,7 +741,8 @@ Error in server response, closing control connection.\n")); logputs (LOG_VERBOSE, "\n"); logprintf (LOG_NOTQUIET, "socket: %s\n", strerror (errno)); CLOSE (csock); - closeport (dtsock); + CLOSE (dtsock); + CLOSE (local_sock); rbuf_uninitialize (&con->rbuf); return err; break; @@ -744,14 +751,16 @@ Error in server response, closing control connection.\n")); logputs (LOG_VERBOSE, "\n"); logprintf (LOG_NOTQUIET, _("Bind error (%s).\n"), strerror (errno)); - closeport (dtsock); + CLOSE (dtsock); + CLOSE (local_sock); return err; break; case FTPPORTERR: logputs (LOG_VERBOSE, "\n"); logputs (LOG_NOTQUIET, _("Invalid PORT.\n")); CLOSE (csock); - closeport (dtsock); + CLOSE (dtsock); + CLOSE (local_sock); rbuf_uninitialize (&con->rbuf); return err; break; @@ -782,7 +791,8 @@ Error in server response, closing control connection.\n")); logputs (LOG_NOTQUIET, _("\ Error in server response, closing control connection.\n")); CLOSE (csock); - closeport (dtsock); + CLOSE (dtsock); + CLOSE (local_sock); rbuf_uninitialize (&con->rbuf); return err; break; @@ -791,7 +801,8 @@ Error in server response, closing control connection.\n")); logputs (LOG_NOTQUIET, _("Write failed, closing control connection.\n")); CLOSE (csock); - closeport (dtsock); + CLOSE (dtsock); + CLOSE (local_sock); rbuf_uninitialize (&con->rbuf); return err; break; @@ -805,7 +816,8 @@ Error in server response, closing control connection.\n")); _("\nREST failed; will not truncate `%s'.\n"), con->target); CLOSE (csock); - closeport (dtsock); + CLOSE (dtsock); + CLOSE (local_sock); rbuf_uninitialize (&con->rbuf); return CONTNOTSUPPORTED; } @@ -832,7 +844,8 @@ Error in server response, closing control connection.\n")); if (opt.spider) { CLOSE (csock); - closeport (dtsock); + CLOSE (dtsock); + CLOSE (local_sock); rbuf_uninitialize (&con->rbuf); return RETRFINISHED; } @@ -856,7 +869,8 @@ Error in server response, closing control connection.\n")); logputs (LOG_NOTQUIET, _("\ Error in server response, closing control connection.\n")); CLOSE (csock); - closeport (dtsock); + CLOSE (dtsock); + CLOSE (local_sock); rbuf_uninitialize (&con->rbuf); return err; break; @@ -865,14 +879,16 @@ Error in server response, closing control connection.\n")); logputs (LOG_NOTQUIET, _("Write failed, closing control connection.\n")); CLOSE (csock); - closeport (dtsock); + CLOSE (dtsock); + CLOSE (local_sock); rbuf_uninitialize (&con->rbuf); return err; break; case FTPNSFOD: logputs (LOG_VERBOSE, "\n"); logprintf (LOG_NOTQUIET, _("No such file `%s'.\n\n"), u->file); - closeport (dtsock); + CLOSE (dtsock); + CLOSE (local_sock); return err; break; case FTPOK: @@ -904,7 +920,8 @@ Error in server response, closing control connection.\n")); logputs (LOG_NOTQUIET, _("\ Error in server response, closing control connection.\n")); CLOSE (csock); - closeport (dtsock); + CLOSE (dtsock); + CLOSE (local_sock); rbuf_uninitialize (&con->rbuf); return err; break; @@ -913,7 +930,8 @@ Error in server response, closing control connection.\n")); logputs (LOG_NOTQUIET, _("Write failed, closing control connection.\n")); CLOSE (csock); - closeport (dtsock); + CLOSE (dtsock); + CLOSE (local_sock); rbuf_uninitialize (&con->rbuf); return err; break; @@ -921,7 +939,8 @@ Error in server response, closing control connection.\n")); logputs (LOG_VERBOSE, "\n"); logprintf (LOG_NOTQUIET, _("No such file or directory `%s'.\n\n"), "."); - closeport (dtsock); + CLOSE (dtsock); + CLOSE (local_sock); return err; break; case FTPOK: @@ -953,7 +972,7 @@ Error in server response, closing control connection.\n")); to accept */ { /* Open the data transmission socket by calling acceptport(). */ - err = acceptport (&dtsock); + err = acceptport (local_sock, &dtsock); /* Possible errors: ACCEPTERR. */ if (err == ACCEPTERR) { @@ -977,7 +996,8 @@ Error in server response, closing control connection.\n")); logprintf (LOG_NOTQUIET, "%s: %s\n", con->target, strerror (errno)); CLOSE (csock); rbuf_uninitialize (&con->rbuf); - closeport (dtsock); + CLOSE (dtsock); + CLOSE (local_sock); return FOPENERR; } } @@ -1024,7 +1044,8 @@ Error in server response, closing control connection.\n")); tms = time_str (NULL); tmrate = retr_rate (*len - restval, con->dltime, 0); /* Close data connection socket. */ - closeport (dtsock); + CLOSE (dtsock); + CLOSE (local_sock); /* Close the local file. */ { /* Close or flush the file. We have to be careful to check for diff --git a/src/ftp.h b/src/ftp.h index 33c4c419..78460016 100644 --- a/src/ftp.h +++ b/src/ftp.h @@ -48,13 +48,13 @@ enum stype uerr_t ftp_response PARAMS ((struct rbuf *, char **)); uerr_t ftp_login PARAMS ((struct rbuf *, const char *, const char *)); -uerr_t ftp_port PARAMS ((struct rbuf *)); -uerr_t ftp_pasv PARAMS ((struct rbuf *, ip_address *, unsigned short *)); +uerr_t ftp_port PARAMS ((struct rbuf *, int *)); +uerr_t ftp_pasv PARAMS ((struct rbuf *, ip_address *, int *)); #ifdef ENABLE_IPV6 -uerr_t ftp_lprt PARAMS ((struct rbuf *)); -uerr_t ftp_lpsv PARAMS ((struct rbuf *, ip_address *, unsigned short *)); -uerr_t ftp_eprt PARAMS ((struct rbuf *)); -uerr_t ftp_epsv PARAMS ((struct rbuf *, ip_address *, unsigned short *)); +uerr_t ftp_lprt PARAMS ((struct rbuf *, int *)); +uerr_t ftp_lpsv PARAMS ((struct rbuf *, ip_address *, int *)); +uerr_t ftp_eprt PARAMS ((struct rbuf *, int *)); +uerr_t ftp_epsv PARAMS ((struct rbuf *, ip_address *, int *)); #endif uerr_t ftp_type PARAMS ((struct rbuf *, int)); uerr_t ftp_cwd PARAMS ((struct rbuf *, const char *)); diff --git a/src/host.c b/src/host.c index 62088aef..937d72c8 100644 --- a/src/host.c +++ b/src/host.c @@ -6,7 +6,7 @@ This file is part of GNU Wget. 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. + (at your option) any later version. GNU Wget is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -99,7 +99,11 @@ struct address_list { ip_address *addresses; /* pointer to the string of addresses */ int faulty; /* number of addresses known not to work. */ - int refcount; /* so we know whether to free it or not. */ + int from_cache; /* whether this entry was pulled from + cache or freshly looked up. */ + + int refcount; /* reference count; when it drops to + 0, the entry is freed. */ }; /* Get the bounds of the address list. */ @@ -111,14 +115,22 @@ address_list_get_bounds (const struct address_list *al, int *start, int *end) *end = al->count; } -/* Copy address number INDEX to IP_STORE. */ +/* Return whether this address list entry has been obtained from the + cache. */ -void -address_list_copy_one (const struct address_list *al, int index, - ip_address *ip_store) +int +address_list_cached_p (const struct address_list *al) +{ + return al->from_cache; +} + +/* Return a pointer to the address at position POS. */ + +const ip_address * +address_list_address_at (const struct address_list *al, int pos) { - assert (index >= al->faulty && index < al->count); - memcpy (ip_store, al->addresses + index, sizeof (ip_address)); + assert (pos >= al->faulty && pos < al->count); + return al->addresses + pos; } /* Check whether two address lists have all their IPs in common. */ @@ -204,7 +216,7 @@ address_list_set_faulty (struct address_list *al, int index) * This function transform an addrinfo links list in and address_list. * * Input: - * addrinfo* Linkt list of addrinfo + * addrinfo* Linked list of addrinfo * * Output: * address_list* New allocated address_list @@ -225,10 +237,11 @@ address_list_from_addrinfo (const struct addrinfo *ai) return NULL; al = xmalloc (sizeof (struct address_list)); - al->addresses = xmalloc (cnt * sizeof (ip_address)); - al->count = cnt; - al->faulty = 0; - al->refcount = 1; + al->addresses = xmalloc (cnt * sizeof (ip_address)); + al->count = cnt; + al->faulty = 0; + al->from_cache = 0; + al->refcount = 1; ip = al->addresses; for (ptr = ai; ptr != NULL; ptr = ptr->ai_next) @@ -268,10 +281,11 @@ address_list_from_vector (char **h_addr_list) ++count; assert (count > 0); - al->count = count; - al->faulty = 0; - al->addresses = xmalloc (count * sizeof (ip_address)); - al->refcount = 1; + al->count = count; + al->faulty = 0; + al->addresses = xmalloc (count * sizeof (ip_address)); + al->from_cache = 0; + al->refcount = 1; for (i = 0; i < count; i++) { @@ -290,10 +304,11 @@ static struct address_list * address_list_from_single (const ip_address *addr) { struct address_list *al = xmalloc (sizeof (struct address_list)); - al->count = 1; - al->faulty = 0; - al->addresses = xmalloc (sizeof (ip_address)); - al->refcount = 1; + al->count = 1; + al->faulty = 0; + al->addresses = xmalloc (sizeof (ip_address)); + al->from_cache = 0; + al->refcount = 1; memcpy (al->addresses, addr, sizeof (ip_address)); return al; @@ -319,203 +334,6 @@ address_list_release (struct address_list *al) } } -/** - * sockaddr_set_address - * - * This function takes a sockaddr struct and fills in the protocol type, - * the port number and the address. If ENABLE_IPV6 is defined, the sa - * parameter should point to a sockaddr_storage structure; if not, it - * should point to a sockaddr_in structure. - * If the address parameter is NULL, the function will use the unspecified - * address (0.0.0.0 for IPv4 and :: for IPv6). - * Unsupported address family will abort the whole programm. - * - * Input: - * struct sockaddr* The space to be filled - * unsigned short The port - * const ip_address The IP address - * - * Return: - * - Only modifies 1st parameter. - */ -void -sockaddr_set_address (struct sockaddr *sa, unsigned short port, - const ip_address *addr) -{ - if (addr->type == IPV4_ADDRESS) - { - struct sockaddr_in *sin = (struct sockaddr_in *)sa; - - sin->sin_family = AF_INET; - sin->sin_port = htons (port); - if (addr == NULL) - sin->sin_addr.s_addr = INADDR_ANY; - else - sin->sin_addr = ADDRESS_IPV4_IN_ADDR (addr); - } -#ifdef ENABLE_IPV6 - else if (addr->type == IPV6_ADDRESS) - { - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; - - sin6->sin6_family = AF_INET6; - sin6->sin6_port = htons (port); - /* #### How can ADDR be NULL? We have dereferenced it above by - accessing addr->type! */ - if (addr == NULL) - { - sin6->sin6_addr = in6addr_any; - /* #### Should we set the scope_id here? */ - } - else - { - sin6->sin6_addr = ADDRESS_IPV6_IN6_ADDR (addr); -#ifdef HAVE_SOCKADDR_IN6_SCOPE_ID - sin6->sin6_scope_id = ADDRESS_IPV6_SCOPE (addr); -#endif - } - } -#endif /* ENABLE_IPV6 */ - else - abort (); -} - -void -sockaddr_get_address (const struct sockaddr *sa, unsigned short *port, - ip_address *addr) -{ - if (sa->sa_family == AF_INET) - { - struct sockaddr_in *sin = (struct sockaddr_in *)sa; - - addr->type = IPV4_ADDRESS; - ADDRESS_IPV4_IN_ADDR (addr) = sin->sin_addr; - if (port != NULL) - *port = ntohs (sin->sin_port); - } -#ifdef ENABLE_IPV6 - else if (sa->sa_family == AF_INET6) - { - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; - - addr->type = IPV6_ADDRESS; - ADDRESS_IPV6_IN6_ADDR (addr) = sin6->sin6_addr; -#ifdef HAVE_SOCKADDR_IN6_SCOPE_ID - ADDRESS_IPV6_SCOPE (addr) = sin6->sin6_scope_id; -#endif - if (port != NULL) - *port = ntohs (sin6->sin6_port); - } -#endif - else - abort (); -} - -#if 0 /* currently unused */ -/** - * sockaddr_set_port - * - * This funtion only fill the port of the socket information. - * If the protocol is not supported nothing is done. - * Unsuported adress family will abort the whole programm. - * - * Require: - * that the IP-Protocol already is set. - * - * Input: - * wget_sockaddr* The space there port should be entered - * unsigned int The port that should be entered in host order - * - * Return: - * - Only modify 1. param - */ -void -sockaddr_set_port (struct sockaddr *sa, unsigned short port) -{ - if (sa->sa_family == AF_INET) - { - struct sockaddr_in *sin = (struct sockaddr_in *)sa; - sin->sin_port = htons (port); - } -#ifdef ENABLE_IPV6 - else if (sa->sa_family == AF_INET6) - { - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; - sin6->sin6_port = htons (port); - } -#endif - else - abort (); -} -#endif - -/** - * sockaddr_get_port - * - * This function only return the port from the input structure - * Unsuported adress family will abort the whole programm. - * - * Require: - * that the IP-Protocol already is set. - * - * Input: - * wget_sockaddr* Information where to get the port - * - * Output: - * unsigned short Port Number in host order. - */ -unsigned short -sockaddr_get_port (const struct sockaddr *sa) -{ - if (sa->sa_family == AF_INET) { - const struct sockaddr_in *sin = (const struct sockaddr_in *)sa; - return htons (sin->sin_port); -#ifdef ENABLE_IPV6 - } else if (sa->sa_family == AF_INET6) { - const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa; - return htons (sin6->sin6_port); -#endif - } else - abort (); - /* do not complain about return nothing */ - return -1; -} - -/** - * sockaddr_len - * - * This function return the length of the sockaddr corresponding to - * the acutall prefered protocol for (bind, connect etc...) - * Unsuported adress family will abort the whole programm. - * - * Require: - * that the IP-Protocol already is set. - * - * Input: - * - Public IP-Family Information - * - * Output: - * int structure length for socket options - */ -socklen_t -sockaddr_len (const struct sockaddr *sa) -{ - if (sa->sa_family == AF_INET) - { - return sizeof (struct sockaddr_in); - } -#ifdef ENABLE_IPV6 - else if (sa->sa_family == AF_INET6) - { - return sizeof (struct sockaddr_in6); - } -#endif - else - abort (); - /* do not complain about return nothing */ - return 0; -} - /* Versions of gethostbyname and getaddrinfo that support timeout. */ #ifndef ENABLE_IPV6 @@ -655,6 +473,17 @@ cache_host_lookup (const char *host, struct address_list *al) #endif } +void +forget_host_lookup (const char *host) +{ + struct address_list *al = hash_table_get (host_name_addresses_map, host); + if (al) + { + address_list_release (al); + hash_table_remove (host_name_addresses_map, host); + } +} + struct address_list * lookup_host (const char *host, int flags) { @@ -724,6 +553,7 @@ lookup_host (const char *host, int flags) { DEBUGP (("Found %s in host_name_addresses_map (%p)\n", host, al)); ++al->refcount; + al->from_cache = 1; return al; } } diff --git a/src/host.h b/src/host.h index d2293dac..22e77038 100644 --- a/src/host.h +++ b/src/host.h @@ -84,12 +84,6 @@ typedef struct { #define ADDRESS_IPV4_IN_ADDR(x) ((x)->u.ipv4.addr) #define ADDRESS_IPV4_DATA(x) ((void *)&(x)->u.ipv4.addr.s_addr) -#ifndef ENABLE_IPV6 -# ifndef HAVE_SOCKADDR_STORAGE -# define sockaddr_storage sockaddr_in -# endif -#endif /* ENABLE_IPV6 */ - /* Flags for lookup_host */ #define LH_SILENT 0x0001 #define LH_PASSIVE 0x0002 @@ -100,10 +94,13 @@ typedef struct { struct address_list *lookup_host PARAMS ((const char *, int)); char *herrmsg PARAMS ((int)); +void forget_host_lookup PARAMS ((const char *)); + void address_list_get_bounds PARAMS ((const struct address_list *, int *, int *)); -void address_list_copy_one PARAMS ((const struct address_list *, int, - ip_address *)); +int address_list_cached_p PARAMS ((const struct address_list *)); +const ip_address *address_list_address_at PARAMS ((const struct address_list *, + int)); int address_list_match_all PARAMS ((const struct address_list *, const struct address_list *)); void address_list_set_faulty PARAMS ((struct address_list *, int)); @@ -114,13 +111,6 @@ const char *pretty_print_address PARAMS ((const ip_address *)); int accept_domain PARAMS ((struct url *)); int sufmatch PARAMS ((const char **, const char *)); -void sockaddr_set_address PARAMS ((struct sockaddr *, unsigned short, - const ip_address *)); -void sockaddr_get_address PARAMS ((const struct sockaddr *, unsigned short *, - ip_address *)); -unsigned short sockaddr_get_port PARAMS ((const struct sockaddr *)); -socklen_t sockaddr_len PARAMS ((const struct sockaddr *sa)); - void host_cleanup PARAMS ((void)); #endif /* HOST_H */ diff --git a/src/http.c b/src/http.c index a3a40d4d..88bb450d 100644 --- a/src/http.c +++ b/src/http.c @@ -744,15 +744,10 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy) #endif /* HAVE_SSL */ ) { - struct address_list *al = lookup_host (conn->host, 0); - if (!al) + sock = connect_to_host (conn->host, conn->port); + if (sock == E_HOST) return HOSTERR; - set_connection_host_name (conn->host); - sock = connect_to_many (al, conn->port, 0); - set_connection_host_name (NULL); - address_list_release (al); - - if (sock < 0) + else if (sock < 0) return CONNECT_ERROR (errno); #ifdef HAVE_SSL diff --git a/src/sysdep.h b/src/sysdep.h index 0d006ecd..96c061b9 100644 --- a/src/sysdep.h +++ b/src/sysdep.h @@ -111,8 +111,8 @@ so, delete this exception statement from your version. */ #ifdef __BEOS__ # undef READ # undef WRITE -# define READ(fd, buf, cnt) recv((fd), (buf), (cnt), 0) -# define WRITE(fd, buf, cnt) send((fd), (buf), (cnt), 0) +# define READ(fd, buf, cnt) recv ((fd), (buf), (cnt), 0) +# define WRITE(fd, buf, cnt) send ((fd), (buf), (cnt), 0) #endif /* mswindows.h defines these. */ @@ -126,10 +126,13 @@ so, delete this exception statement from your version. */ # define REALCLOSE(x) close (x) #endif -#define CLOSE(x) \ -do { \ - REALCLOSE (x); \ - DEBUGP (("Closing fd %d\n", x)); \ +#define CLOSE(x) do { \ + int C_sock = (x); \ + if (C_sock >= 0) \ + { \ + REALCLOSE (C_sock); \ + DEBUGP (("Closing fd %d\n", C_sock)); \ + } \ } while (0) /* Define a large integral type useful for storing large sizes that -- 2.39.2