+/* 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
+test_socket_open (int sock)
+{
+ 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 (select (sock + 1, &check_set, NULL, NULL, &to) == 0)
+ /* 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;