+accept_connection (int local_sock)
+{
+ int sock;
+
+ /* We don't need the values provided by accept, but accept
+ apparently requires them to be present. */
+ struct sockaddr_storage ss;
+ struct sockaddr *sa = (struct sockaddr *)&ss;
+ socklen_t addrlen = sizeof (ss);
+
+ if (opt.connect_timeout)
+ {
+ int test = select_fd (local_sock, opt.connect_timeout, WAIT_FOR_READ);
+ if (test == 0)
+ errno = ETIMEDOUT;
+ if (test <= 0)
+ return -1;
+ }
+ sock = accept (local_sock, sa, &addrlen);
+ DEBUGP (("Accepted client at socket %d.\n", sock));
+ return sock;
+}
+
+/* Get the IP address associated with the connection on FD and store
+ it to IP. Return true on success, false otherwise.
+
+ If ENDPOINT is ENDPOINT_LOCAL, it returns the address of the local
+ (client) side of the socket. Else if ENDPOINT is ENDPOINT_PEER, it
+ returns the address of the remote (peer's) side of the socket. */
+
+bool
+socket_ip_address (int sock, ip_address *ip, int endpoint)
+{
+ struct sockaddr_storage storage;
+ struct sockaddr *sockaddr = (struct sockaddr *)&storage;
+ socklen_t addrlen = sizeof (storage);
+ int ret;
+
+ if (endpoint == ENDPOINT_LOCAL)
+ ret = getsockname (sock, sockaddr, &addrlen);
+ else if (endpoint == ENDPOINT_PEER)
+ ret = getpeername (sock, sockaddr, &addrlen);
+ else
+ abort ();
+ 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->data.d6 = sa6->sin6_addr;
+#ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
+ ip->ipv6_scope = sa6->sin6_scope_id;
+#endif
+ DEBUGP (("conaddr is: %s\n", print_address (ip)));
+ return true;
+ }
+#endif
+ case AF_INET:
+ {
+ struct sockaddr_in *sa = (struct sockaddr_in *)&storage;
+ ip->data.d4 = sa->sin_addr;
+ DEBUGP (("conaddr is: %s\n", print_address (ip)));
+ return true;
+ }
+ default:
+ abort ();
+ }
+}
+
+/* Return true if the error from the connect code can be considered
+ retryable. Wget normally retries after errors, but the exception
+ are the "unsupported protocol" type errors (possible on IPv4/IPv6
+ dual family systems) and "connection refused". */
+
+bool
+retryable_socket_connect_error (int err)
+{
+ /* Have to guard against some of these values not being defined.
+ Cannot use a switch statement because some of the values might be
+ equal. */
+ if (false
+#ifdef EAFNOSUPPORT
+ || err == EAFNOSUPPORT
+#endif
+#ifdef EPFNOSUPPORT
+ || err == EPFNOSUPPORT
+#endif
+#ifdef ESOCKTNOSUPPORT /* no, "sockt" is not a typo! */
+ || err == ESOCKTNOSUPPORT
+#endif
+#ifdef EPROTONOSUPPORT
+ || err == EPROTONOSUPPORT
+#endif
+#ifdef ENOPROTOOPT
+ || err == ENOPROTOOPT
+#endif
+ /* Apparently, older versions of Linux and BSD used EINVAL
+ instead of EAFNOSUPPORT and such. */
+ || err == EINVAL
+ )
+ return false;
+
+ if (!opt.retry_connrefused)
+ if (err == ECONNREFUSED
+#ifdef ENETUNREACH
+ || err == ENETUNREACH /* network is unreachable */
+#endif
+#ifdef EHOSTUNREACH
+ || err == EHOSTUNREACH /* host is unreachable */
+#endif
+ )
+ return false;
+
+ return true;
+}
+
+/* Wait for a single descriptor to become available, timing out after
+ MAXTIME seconds. Returns 1 if FD is available, 0 for timeout and
+ -1 for error. The argument WAIT_FOR can be a combination of
+ WAIT_FOR_READ and WAIT_FOR_WRITE.
+
+ This is a mere convenience wrapper around the select call, and
+ should be taken as such (for example, it doesn't implement Wget's
+ 0-timeout-means-no-timeout semantics.) */
+
+int
+select_fd (int fd, double maxtime, int wait_for)
+{
+ fd_set fdset;
+ fd_set *rd = NULL, *wr = NULL;
+ struct timeval tmout;
+ int result;
+
+ FD_ZERO (&fdset);
+ FD_SET (fd, &fdset);
+ if (wait_for & WAIT_FOR_READ)
+ rd = &fdset;
+ if (wait_for & WAIT_FOR_WRITE)
+ wr = &fdset;
+
+ tmout.tv_sec = (long) maxtime;
+ tmout.tv_usec = 1000000 * (maxtime - (long) maxtime);
+
+ do
+ result = select (fd + 1, rd, wr, NULL, &tmout);
+ while (result < 0 && errno == EINTR);
+
+ 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