+#ifdef HAVE_RFC2553
+/* Getaddrinfo implementation */
+jb_socket connect_to(const char *host, int portnum, struct client_state *csp)
+{
+ struct addrinfo hints, *result, *rp;
+ char service[6];
+ int retval;
+ jb_socket fd;
+ fd_set wfds;
+ struct timeval tv[1];
+#if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA)
+ int flags;
+#endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) */
+ int connect_failed;
+
+#ifdef FEATURE_ACL
+ struct access_control_addr dst[1];
+#endif /* def FEATURE_ACL */
+
+ retval = snprintf(service, sizeof(service), "%d", portnum);
+ if ((-1 == retval) || (sizeof(service) <= retval))
+ {
+ log_error(LOG_LEVEL_ERROR,
+ "Port number (%d) ASCII decimal representation doesn't fit into 6 bytes",
+ portnum);
+ csp->http->host_ip_addr_str = strdup("unknown");
+ return(JB_INVALID_SOCKET);
+ }
+
+ memset((char *)&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV; /* avoid service look-up */
+ if ((retval = getaddrinfo(host, service, &hints, &result)))
+ {
+ log_error(LOG_LEVEL_INFO,
+ "Can not resolve %s: %s", host, gai_strerror(retval));
+ csp->http->host_ip_addr_str = strdup("unknown");
+ return(JB_INVALID_SOCKET);
+ }
+
+ for (rp = result; rp != NULL; rp = rp->ai_next)
+ {
+
+#ifdef FEATURE_ACL
+ memcpy(&dst->addr, rp->ai_addr, rp->ai_addrlen);
+
+ if (block_acl(dst, csp))
+ {
+#ifdef __OS2__
+ errno = SOCEPERM;
+#else
+ errno = EPERM;
+#endif
+ continue;
+ }
+#endif /* def FEATURE_ACL */
+
+ csp->http->host_ip_addr_str = malloc(NI_MAXHOST);
+ retval = getnameinfo(rp->ai_addr, rp->ai_addrlen,
+ csp->http->host_ip_addr_str, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
+ if (!csp->http->host_ip_addr_str || retval)
+ {
+ log_error(LOG_LEVEL_ERROR,
+ "Can not save csp->http->host_ip_addr_str: %s",
+ (csp->http->host_ip_addr_str) ?
+ gai_strerror(retval) : "Insufficient memory");
+ freez(csp->http->host_ip_addr_str);
+ continue;
+ }
+
+#ifdef _WIN32
+ if ((fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) ==
+ JB_INVALID_SOCKET)
+#else
+ if ((fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) < 0)
+#endif
+ {
+ continue;
+ }
+
+#ifdef TCP_NODELAY
+ { /* turn off TCP coalescence */
+ int mi = 1;
+ setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &mi, sizeof (int));
+ }
+#endif /* def TCP_NODELAY */
+
+#if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__)
+ if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
+ {
+ flags |= O_NDELAY;
+ fcntl(fd, F_SETFL, flags);
+ }
+#endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) */
+
+ connect_failed = 0;
+ while (connect(fd, rp->ai_addr, rp->ai_addrlen) == JB_INVALID_SOCKET)
+ {
+#ifdef _WIN32
+ if (errno == WSAEINPROGRESS)
+#elif __OS2__
+ if (sock_errno() == EINPROGRESS)
+#else /* ifndef _WIN32 */
+ if (errno == EINPROGRESS)
+#endif /* ndef _WIN32 || __OS2__ */
+ {
+ break;
+ }
+
+#ifdef __OS2__
+ if (sock_errno() != EINTR)
+#else
+ if (errno != EINTR)
+#endif /* __OS2__ */
+ {
+ close_socket(fd);
+ connect_failed = 1;
+ break;
+ }
+ }
+ if (connect_failed)
+ {
+ continue;
+ }
+
+#if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__)
+ if (flags != -1)
+ {
+ flags &= ~O_NDELAY;
+ fcntl(fd, F_SETFL, flags);
+ }
+#endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) */
+
+ /* wait for connection to complete */
+ FD_ZERO(&wfds);
+ FD_SET(fd, &wfds);
+
+ tv->tv_sec = 30;
+ tv->tv_usec = 0;
+
+ /* MS Windows uses int, not SOCKET, for the 1st arg of select(). Wierd! */
+ if ((select((int)fd + 1, NULL, &wfds, NULL, tv) > 0)
+ && FD_ISSET(fd, &wfds))
+ {
+ /*
+ * See Linux connect(2) man page for more info
+ * about connecting on non-blocking socket.
+ */
+ int socket_in_error;
+ socklen_t optlen = sizeof(socket_in_error);
+ if (!getsockopt(fd, SOL_SOCKET, SO_ERROR, &socket_in_error, &optlen))
+ {
+ if (!socket_in_error)
+ {
+ /* Connection established, no need to try other addresses. */
+ break;
+ }
+ log_error(LOG_LEVEL_CONNECT, "Could not connect to [%s]:%s: %s.",
+ csp->http->host_ip_addr_str, service, strerror(socket_in_error));
+ }
+ else
+ {
+ log_error(LOG_LEVEL_ERROR, "Could not get the state of "
+ "the connection to [%s]:%s: %s; dropping connection.",
+ csp->http->host_ip_addr_str, service, strerror(errno));
+ }
+ }
+
+ /* Connection failed, try next address */
+ close_socket(fd);
+ }
+
+ freeaddrinfo(result);
+ if (!rp)
+ {
+ log_error(LOG_LEVEL_CONNECT, "Could not connect to [%s]:%s.",
+ host, service);
+ return(JB_INVALID_SOCKET);
+ }
+ log_error(LOG_LEVEL_CONNECT, "Connected to %s[%s]:%s.",
+ host, csp->http->host_ip_addr_str, service);
+
+ return(fd);
+
+}
+
+#else /* ndef HAVE_RFC2553 */
+/* Pre-getaddrinfo implementation */
+
+jb_socket connect_to(const char *host, int portnum, struct client_state *csp)