X-Git-Url: http://sjero.net/git/?a=blobdiff_plain;f=src%2Fconnect.c;h=ab1fd08e7a03e7430136622db3ab54e3b274ac05;hb=4d7c5e087b2bc82c9f503dff003916d1047903ce;hp=5278de78a203a5c8717511de320ab5593b0ecb4e;hpb=c1fb83c53b27ffd1635fda24702f2a115d939511;p=wget diff --git a/src/connect.c b/src/connect.c index 5278de78..ab1fd08e 100644 --- a/src/connect.c +++ b/src/connect.c @@ -1,11 +1,11 @@ /* Establishing and handling network connections. - Copyright (C) 1995, 1996, 1997, 2001, 2002 Free Software Foundation, Inc. + Copyright (C) 1996-2006 Free Software Foundation, Inc. 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 +the Free Software Foundation; either version 3 of the License, or (at your option) any later version. GNU Wget is distributed in the hope that it will be useful, @@ -14,8 +14,7 @@ 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 Wget; if not, write to the Free Software -Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +along with Wget. If not, see . In addition, as a special exception, the Free Software Foundation gives permission to link the code of its release of Wget with the @@ -73,27 +72,27 @@ so, delete this exception statement from your version. */ static void sockaddr_set_data (struct sockaddr *sa, const ip_address *ip, int port) { - switch (ip->type) + switch (ip->family) { - case IPV4_ADDRESS: + case AF_INET: { struct sockaddr_in *sin = (struct sockaddr_in *)sa; xzero (*sin); sin->sin_family = AF_INET; sin->sin_port = htons (port); - sin->sin_addr = ADDRESS_IPV4_IN_ADDR (ip); + sin->sin_addr = ip->data.d4; break; } #ifdef ENABLE_IPV6 - case IPV6_ADDRESS: + case AF_INET6: { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; xzero (*sin6); sin6->sin6_family = AF_INET6; sin6->sin6_port = htons (port); - sin6->sin6_addr = ADDRESS_IPV6_IN6_ADDR (ip); + sin6->sin6_addr = ip->data.d6; #ifdef HAVE_SOCKADDR_IN6_SCOPE_ID - sin6->sin6_scope_id = ADDRESS_IPV6_SCOPE (ip); + sin6->sin6_scope_id = ip->ipv6_scope; #endif break; } @@ -117,8 +116,8 @@ sockaddr_get_data (const struct sockaddr *sa, ip_address *ip, int *port) struct sockaddr_in *sin = (struct sockaddr_in *)sa; if (ip) { - ip->type = IPV4_ADDRESS; - ADDRESS_IPV4_IN_ADDR (ip) = sin->sin_addr; + ip->family = AF_INET; + ip->data.d4 = sin->sin_addr; } if (port) *port = ntohs (sin->sin_port); @@ -130,10 +129,10 @@ sockaddr_get_data (const struct sockaddr *sa, ip_address *ip, int *port) struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; if (ip) { - ip->type = IPV6_ADDRESS; - ADDRESS_IPV6_IN6_ADDR (ip) = sin6->sin6_addr; + ip->family = AF_INET6; + ip->data.d6 = sin6->sin6_addr; #ifdef HAVE_SOCKADDR_IN6_SCOPE_ID - ADDRESS_IPV6_SCOPE (ip) = sin6->sin6_scope_id; + ip->ipv6_scope = sin6->sin6_scope_id; #endif } if (port) @@ -415,7 +414,6 @@ int bind_local (const ip_address *bind_address, int *port) { int sock; - int family = AF_INET; struct sockaddr_storage ss; struct sockaddr *sa = (struct sockaddr *)&ss; @@ -424,12 +422,7 @@ bind_local (const ip_address *bind_address, int *port) void *setopt_ptr = (void *)&setopt_val; socklen_t setopt_size = sizeof (setopt_val); -#ifdef ENABLE_IPV6 - if (bind_address->type == IPV6_ADDRESS) - family = AF_INET6; -#endif - - sock = socket (family, SOCK_STREAM, 0); + sock = socket (bind_address->family, SOCK_STREAM, 0); if (sock < 0) return -1; @@ -529,16 +522,16 @@ socket_ip_address (int sock, ip_address *ip, int endpoint) if (ret < 0) return false; + ip->family = sockaddr->sa_family; switch (sockaddr->sa_family) { #ifdef ENABLE_IPV6 case AF_INET6: { struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)&storage; - ip->type = IPV6_ADDRESS; - ADDRESS_IPV6_IN6_ADDR (ip) = sa6->sin6_addr; + ip->data.d6 = sa6->sin6_addr; #ifdef HAVE_SOCKADDR_IN6_SCOPE_ID - ADDRESS_IPV6_SCOPE (ip) = sa6->sin6_scope_id; + ip->ipv6_scope = sa6->sin6_scope_id; #endif DEBUGP (("conaddr is: %s\n", print_address (ip))); return true; @@ -547,8 +540,7 @@ socket_ip_address (int sock, ip_address *ip, int endpoint) case AF_INET: { struct sockaddr_in *sa = (struct sockaddr_in *)&storage; - ip->type = IPV4_ADDRESS; - ADDRESS_IPV4_IN_ADDR (ip) = sa->sin_addr; + ip->data.d4 = sa->sin_addr; DEBUGP (("conaddr is: %s\n", print_address (ip))); return true; } @@ -638,6 +630,17 @@ select_fd (int fd, double maxtime, int wait_for) return result; } +/* Return true iff the connection to the remote site established + through SOCK is still open. + + Specifically, this function returns true if SOCK is not ready for + reading. This is because, when the connection closes, the socket + is ready for reading because EOF is about to be delivered. A side + effect of this method is that sockets that have pending data are + considered non-open. This is actually a good thing for callers of + this function, where such pending data can only be unwanted + leftover from a previous request. */ + bool test_socket_open (int sock) { @@ -654,13 +657,12 @@ test_socket_open (int sock) 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 true; - } + /* We got a timeout, it means we're still connected. */ + return true; else + /* Read now would not wait, it means we have either pending data + or EOF/error. */ return false; } @@ -732,14 +734,10 @@ sock_close (int fd) or SSL_read or whatever is necessary. */ static struct hash_table *transport_map; -static int transport_map_modified_tick; +static unsigned int transport_map_modified_tick; struct transport_info { - fd_reader_t reader; - fd_writer_t writer; - fd_poller_t poller; - fd_peeker_t peeker; - fd_closer_t closer; + struct transport_implementation *imp; void *ctx; }; @@ -751,9 +749,7 @@ struct transport_info { call getpeername, etc. */ void -fd_register_transport (int fd, fd_reader_t reader, fd_writer_t writer, - fd_poller_t poller, fd_peeker_t peeker, - fd_closer_t closer, void *ctx) +fd_register_transport (int fd, struct transport_implementation *imp, void *ctx) { struct transport_info *info; @@ -763,15 +759,11 @@ fd_register_transport (int fd, fd_reader_t reader, fd_writer_t writer, assert (fd >= 0); info = xnew (struct transport_info); - info->reader = reader; - info->writer = writer; - info->poller = poller; - info->peeker = peeker; - info->closer = closer; + info->imp = imp; info->ctx = ctx; if (!transport_map) transport_map = hash_table_new (0, NULL, NULL); - hash_table_put (transport_map, (void *) fd, info); + hash_table_put (transport_map, (void *)(intptr_t) fd, info); ++transport_map_modified_tick; } @@ -782,7 +774,7 @@ fd_register_transport (int fd, fd_reader_t reader, fd_writer_t writer, void * fd_transport_context (int fd) { - struct transport_info *info = hash_table_get (transport_map, (void *) fd); + struct transport_info *info = hash_table_get (transport_map, (void *)(intptr_t) fd); return info->ctx; } @@ -797,14 +789,15 @@ fd_transport_context (int fd) #define LAZY_RETRIEVE_INFO(info) do { \ static struct transport_info *last_info; \ - static int last_fd = -1, last_tick; \ + static int last_fd = -1; \ + static unsigned int last_tick; \ if (!transport_map) \ info = NULL; \ else if (last_fd == fd && last_tick == transport_map_modified_tick) \ info = last_info; \ else \ { \ - info = hash_table_get (transport_map, (void *) fd); \ + info = hash_table_get (transport_map, (void *)(intptr_t) fd); \ last_fd = fd; \ last_info = info; \ last_tick = transport_map_modified_tick; \ @@ -819,8 +812,8 @@ poll_internal (int fd, struct transport_info *info, int wf, double timeout) if (timeout) { int test; - if (info && info->poller) - test = info->poller (fd, timeout, wf, info->ctx); + if (info && info->imp->poller) + test = info->imp->poller (fd, timeout, wf, info->ctx); else test = sock_poll (fd, timeout, wf); if (test == 0) @@ -843,8 +836,8 @@ fd_read (int fd, char *buf, int bufsize, double timeout) LAZY_RETRIEVE_INFO (info); if (!poll_internal (fd, info, WAIT_FOR_READ, timeout)) return -1; - if (info && info->reader) - return info->reader (fd, buf, bufsize, info->ctx); + if (info && info->imp->reader) + return info->imp->reader (fd, buf, bufsize, info->ctx); else return sock_read (fd, buf, bufsize); } @@ -868,8 +861,8 @@ fd_peek (int fd, char *buf, int bufsize, double timeout) LAZY_RETRIEVE_INFO (info); if (!poll_internal (fd, info, WAIT_FOR_READ, timeout)) return -1; - if (info && info->peeker) - return info->peeker (fd, buf, bufsize, info->ctx); + if (info && info->imp->peeker) + return info->imp->peeker (fd, buf, bufsize, info->ctx); else return sock_peek (fd, buf, bufsize); } @@ -893,8 +886,8 @@ fd_write (int fd, char *buf, int bufsize, double timeout) { if (!poll_internal (fd, info, WAIT_FOR_WRITE, timeout)) return -1; - if (info && info->writer) - res = info->writer (fd, buf, bufsize, info->ctx); + if (info && info->imp->writer) + res = info->imp->writer (fd, buf, bufsize, info->ctx); else res = sock_write (fd, buf, bufsize); if (res <= 0) @@ -905,6 +898,35 @@ fd_write (int fd, char *buf, int bufsize, double timeout) return res; } +/* Report the most recent error(s) on FD. This should only be called + after fd_* functions, such as fd_read and fd_write, and only if + they return a negative result. For errors coming from other calls + such as setsockopt or fopen, strerror should continue to be + used. + + If the transport doesn't support error messages or doesn't supply + one, strerror(errno) is returned. The returned error message + should not be used after fd_close has been called. */ + +const char * +fd_errstr (int fd) +{ + /* Don't bother with LAZY_RETRIEVE_INFO, as this will only be called + in case of error, never in a tight loop. */ + struct transport_info *info = NULL; + if (transport_map) + info = hash_table_get (transport_map, (void *)(intptr_t) fd); + + if (info && info->imp->errstr) + { + const char *err = info->imp->errstr (fd, info->ctx); + if (err) + return err; + /* else, fall through and print the system error. */ + } + return strerror (errno); +} + /* Close the file descriptor FD. */ void @@ -918,16 +940,16 @@ fd_close (int fd) per socket, so that particular optimization wouldn't work. */ info = NULL; if (transport_map) - info = hash_table_get (transport_map, (void *) fd); + info = hash_table_get (transport_map, (void *)(intptr_t) fd); - if (info && info->closer) - info->closer (fd, info->ctx); + if (info && info->imp->closer) + info->imp->closer (fd, info->ctx); else sock_close (fd); if (info) { - hash_table_remove (transport_map, (void *) fd); + hash_table_remove (transport_map, (void *)(intptr_t) fd); xfree (info); ++transport_map_modified_tick; }