-const char jbsockets_rcs[] = "$Id: jbsockets.c,v 1.43 2007/06/01 18:16:36 fabiankeil Exp $";
+const char jbsockets_rcs[] = "$Id: jbsockets.c,v 1.54 2009/04/17 11:45:19 fabiankeil Exp $";
/*********************************************************************
*
* File : $Source: /cvsroot/ijbswa/current/jbsockets.c,v $
* OS-independent. Contains #ifdefs to make this work
* on many platforms.
*
- * Copyright : Written by and Copyright (C) 2001-2007 the SourceForge
+ * Copyright : Written by and Copyright (C) 2001-2009 the
* Privoxy team. http://www.privoxy.org/
*
* Based on the Internet Junkbuster originally written
*
* Revisions :
* $Log: jbsockets.c,v $
+ * Revision 1.54 2009/04/17 11:45:19 fabiankeil
+ * Replace HAVE_GETADDRINFO and HAVE_GETNAMEINFO macros
+ * with HAVE_RFC2553 macro. Original patch by Petr Pisar.
+ *
+ * Revision 1.53 2009/04/17 11:39:52 fabiankeil
+ * If the hostname is 'localhost' or not specified, request an AF_INET address.
+ *
+ * Revision 1.52 2009/04/17 11:34:34 fabiankeil
+ * Style cosmetics for the IPv6 code.
+ *
+ * Revision 1.51 2009/04/17 11:27:49 fabiankeil
+ * Petr Pisar's privoxy-3.0.12-ipv6-3.diff.
+ *
+ * Revision 1.50 2008/12/20 14:53:55 fabiankeil
+ * Add config option socket-timeout to control the time
+ * Privoxy waits for data to arrive on a socket. Useful
+ * in case of stale ssh tunnels or when fuzz-testing.
+ *
+ * Revision 1.49 2008/11/10 17:03:57 fabiankeil
+ * Fix a gcc44 warning and remove a now-obsolete cast.
+ *
+ * Revision 1.48 2008/09/04 08:13:58 fabiankeil
+ * Prepare for critical sections on Windows by adding a
+ * layer of indirection before the pthread mutex functions.
+ *
+ * Revision 1.47 2008/03/26 18:07:07 fabiankeil
+ * Add hostname directive. Closes PR#1918189.
+ *
+ * Revision 1.46 2008/03/21 11:13:57 fabiankeil
+ * Only gather host information if it's actually needed.
+ * Also move the code out of accept_connection() so it's less likely
+ * to delay other incoming connections if the host is misconfigured.
+ *
+ * Revision 1.45 2007/09/30 16:59:22 fabiankeil
+ * Set the maximum listen() backlog to 128. Apparently SOMAXCONN is
+ * neither high enough, nor a hard limit on mingw32. Again for BR#1795281.
+ *
+ * Revision 1.44 2007/09/15 13:01:31 fabiankeil
+ * Increase listen() backlog to SOMAXCONN (or 128) to decrease
+ * chances of dropped connections under load. Problem reported
+ * and fix suggested by nobody in BR#1795281.
+ *
* Revision 1.43 2007/06/01 18:16:36 fabiankeil
* Use the same mutex for gethostbyname() and gethostbyaddr() to prevent
* deadlocks and crashes on OpenBSD and possibly other OS with neither
#endif
+#ifdef FEATURE_CONNECTION_KEEP_ALIVE
+#ifdef HAVE_POLL
+#ifdef __GLIBC__
+#include <sys/poll.h>
+#else
+#include <poll.h>
+#endif /* def __GLIBC__ */
+#endif /* HAVE_POLL */
+#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
+
#include "project.h"
#ifdef FEATURE_PTHREAD
#include "jbsockets.h"
#include "filters.h"
#include "errlog.h"
+#include "miscutil.h"
const char jbsockets_h_rcs[] = JBSOCKETS_H_VERSION;
*/
#define MAX_DNS_RETRIES 10
-#ifndef SOMAXCONN
-/* XXX: Might not be necessary. */
-#define SOMAXCONN 128
-#endif
+#define MAX_LISTEN_BACKLOG 128
+
/*********************************************************************
*
*
* Parameters :
* 1 : host = hostname to connect to
- * 2 : portnum = port to connent on
+ * 2 : portnum = port to connent on (XXX: should be unsigned)
* 3 : csp = Current client state (buffers, headers, etc...)
* Not modified, only used for source IP and ACL.
*
* file descriptor.
*
*********************************************************************/
+#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)
+ {
+ close_socket(fd);
+ continue;
+ }
+
+ break; /* for; Connection established; don't try other addresses */
+ }
+
+ freeaddrinfo(result);
+ if (!rp)
+ {
+ log_error(LOG_LEVEL_INFO,
+ "Could not connect to TCP/[%s]:%s", host, service);
+ return(JB_INVALID_SOCKET);
+ }
+ /*
+ * XXX: Current connection verification (EINPROGRESS && select()
+ * for writing) is not sufficient. E.g. on Linux-2.6.27 with glibc-2.6
+ * select returns socket ready for writing, however subsequential
+ * write(2) fails with ENOCONNECT. Read Linux connect(2) man page
+ * about non-blocking sockets.
+ * Thus we can't log here that the socket is connected.
+ */
+ /* log_error(LOG_LEVEL_INFO, "Connected to TCP/[%s]:%s", host, service); */
+
+ return(fd);
+
+}
+
+#else /* ndef HAVE_RFC2553 */
+/* Pre-getaddrinfo implementation */
+
jb_socket connect_to(const char *host, int portnum, struct client_state *csp)
{
struct sockaddr_in inaddr;
jb_socket fd;
- int addr;
+ unsigned int addr;
fd_set wfds;
struct timeval tv[1];
#if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA)
}
#ifdef FEATURE_ACL
- dst->addr = ntohl((unsigned long) addr);
+ dst->addr = ntohl(addr);
dst->port = portnum;
if (block_acl(dst, csp))
return(fd);
}
+#endif /* ndef HAVE_RFC2553 */
/*********************************************************************
}
+/*********************************************************************
+ *
+ * Function : data_is_available
+ *
+ * Description : Waits for data to arrive on a socket.
+ *
+ * Parameters :
+ * 1 : fd = file descriptor of the socket to read
+ * 2 : seconds_to_wait = number of seconds after which we give up.
+ *
+ * Returns : TRUE if data arrived in time,
+ * FALSE otherwise.
+ *
+ *********************************************************************/
+int data_is_available(jb_socket fd, int seconds_to_wait)
+{
+ fd_set rfds;
+ struct timeval timeout;
+ int n;
+
+ memset(&timeout, 0, sizeof(timeout));
+ timeout.tv_sec = seconds_to_wait;
+
+#ifdef __OS2__
+ /* Copy and pasted from jcc.c ... */
+ memset(&rfds, 0, sizeof(fd_set));
+#else
+ FD_ZERO(&rfds);
+#endif
+ FD_SET(fd, &rfds);
+
+ n = select(fd+1, &rfds, NULL, NULL, &timeout);
+
+ /*
+ * XXX: Do we care about the different error conditions?
+ */
+ return (n == 1);
+}
+
+
/*********************************************************************
*
* Function : close_socket
*********************************************************************/
int bind_port(const char *hostnam, int portnum, jb_socket *pfd)
{
+#ifdef HAVE_RFC2553
+ struct addrinfo hints;
+ struct addrinfo *result, *rp;
+ /*
+ * XXX: portnum should be a string to allow symbolic service
+ * names in the configuration file and to avoid the following
+ * int2string.
+ */
+ char servnam[6];
+ int retval;
+#else
struct sockaddr_in inaddr;
+#endif /* def HAVE_RFC2553 */
jb_socket fd;
#ifndef _WIN32
int one = 1;
*pfd = JB_INVALID_SOCKET;
+#ifdef HAVE_RFC2553
+ retval = snprintf(servnam, sizeof(servnam), "%d", portnum);
+ if ((-1 == retval) || (sizeof(servnam) <= retval))
+ {
+ log_error(LOG_LEVEL_ERROR,
+ "Port number (%d) ASCII decimal representation doesn't fit into 6 bytes",
+ portnum);
+ return -1;
+ }
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+ if ((hostnam == NULL) || !strcmpic(hostnam, "localhost"))
+ {
+ /*
+ * XXX: This is a hack. The right thing to do
+ * would be to bind to both AF_INET and AF_INET6.
+ * This will also fail if there is no AF_INET
+ * version available.
+ */
+ hints.ai_family = AF_INET;
+ }
+ else
+ {
+ hints.ai_family = AF_UNSPEC;
+ }
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
+ hints.ai_protocol = 0; /* Realy any stream protocol or TCP only */
+ hints.ai_canonname = NULL;
+ hints.ai_addr = NULL;
+ hints.ai_next = NULL;
+
+ if ((retval = getaddrinfo(hostnam, servnam, &hints, &result)))
+ {
+ log_error(LOG_LEVEL_ERROR,
+ "Can not resolve %s: %s", hostnam, gai_strerror(retval));
+ return -2;
+ }
+#else
memset((char *)&inaddr, '\0', sizeof inaddr);
inaddr.sin_family = AF_INET;
inaddr.sin_port = htonl((unsigned long) portnum);
}
#endif /* ndef _WIN32 */
+#endif /* def HAVE_RFC2553 */
+#ifdef HAVE_RFC2553
+ for (rp = result; rp != NULL; rp = rp->ai_next)
+ {
+ fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
+#else
fd = socket(AF_INET, SOCK_STREAM, 0);
+#endif /* def HAVE_RFC2553 */
#ifdef _WIN32
if (fd == JB_INVALID_SOCKET)
if (fd < 0)
#endif
{
+#ifdef HAVE_RFC2553
+ continue;
+#else
return(-1);
+#endif
}
#ifndef _WIN32
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one));
#endif /* ndef _WIN32 */
+#ifdef HAVE_RFC2553
+ if (bind(fd, rp->ai_addr, rp->ai_addrlen) < 0)
+#else
if (bind(fd, (struct sockaddr *)&inaddr, sizeof(inaddr)) < 0)
+#endif
{
#ifdef _WIN32
errno = WSAGetLastError();
if (errno == EADDRINUSE)
#endif
{
+#ifdef HAVE_RFC2553
+ freeaddrinfo(result);
+#endif
close_socket(fd);
return(-3);
}
else
{
close_socket(fd);
+#ifndef HAVE_RFC2553
return(-1);
}
}
+#else
+ }
+ }
+ else
+ {
+ /* bind() succeeded, escape from for-loop */
+ /*
+ * XXX: Support multiple listening sockets (e.g. localhost
+ * resolves to AF_INET and AF_INET6, but only the first address
+ * is used
+ */
+ break;
+ }
+ }
+
+ freeaddrinfo(result);
+ if (rp == NULL)
+ {
+ /* All bind()s failed */
+ return(-1);
+ }
+#endif /* ndef HAVE_RFC2553 */
- while (listen(fd, SOMAXCONN) == -1)
+ while (listen(fd, MAX_LISTEN_BACKLOG) == -1)
{
if (errno != EINTR)
{
/*********************************************************************
*
- * Function : accept_connection
+ * Function : get_host_information
*
- * Description : Accepts a connection on a socket. Socket must have
- * been created using bind_port().
+ * Description : Determines the IP address the client used to
+ * reach us and the hostname associated with it.
+ *
+ * XXX: Most of the code has been copy and pasted
+ * from accept_connection() and not all of the
+ * ifdefs paths have been tested afterwards.
*
* Parameters :
- * 1 : csp = Client state, cfd, ip_addr_str, and
- * ip_addr_long will be set by this routine.
- * 2 : fd = file descriptor returned from bind_port
+ * 1 : afd = File descriptor returned from accept().
+ * 2 : ip_address = Pointer to return the pointer to
+ * the ip address string.
+ * 3 : hostname = Pointer to return the pointer to
+ * the hostname or NULL if the caller
+ * isn't interested in it.
*
- * Returns : when a connection is accepted, it returns 1 (TRUE).
- * On an error it returns 0 (FALSE).
+ * Returns : void.
*
*********************************************************************/
-int accept_connection(struct client_state * csp, jb_socket fd)
+void get_host_information(jb_socket afd, char **ip_address, char **hostname)
{
- struct sockaddr_in client, server;
+#ifdef HAVE_RFC2553
+ struct sockaddr_storage server;
+ int retval;
+#else
+ struct sockaddr_in server;
struct hostent *host = NULL;
- jb_socket afd;
+#endif /* HAVE_RFC2553 */
#if defined(_WIN32) || defined(__OS2__) || defined(__APPLE_CC__) || defined(AMIGA)
- /* Wierdness - fix a warning. */
- int c_length, s_length;
+ /* according to accept_connection() this fixes a warning. */
+ int s_length, s_length_provided;
#else
- socklen_t c_length, s_length;
+ socklen_t s_length, s_length_provided;
#endif
+#ifndef HAVE_RFC2553
#if defined(HAVE_GETHOSTBYADDR_R_8_ARGS) || defined(HAVE_GETHOSTBYADDR_R_7_ARGS) || defined(HAVE_GETHOSTBYADDR_R_5_ARGS)
struct hostent result;
#if defined(HAVE_GETHOSTBYADDR_R_5_ARGS)
int thd_err;
#endif /* def HAVE_GETHOSTBYADDR_R_5_ARGS */
#endif /* def HAVE_GETHOSTBYADDR_R_(8|7|5)_ARGS */
+#endif /* ifndef HAVE_RFC2553 */
+ s_length = s_length_provided = sizeof(server);
- c_length = s_length = sizeof(client);
-
-#ifdef _WIN32
- afd = accept (fd, (struct sockaddr *) &client, &c_length);
- if (afd == JB_INVALID_SOCKET)
- {
- return 0;
- }
-#else
- do
- {
- afd = accept (fd, (struct sockaddr *) &client, &c_length);
- } while (afd < 1 && errno == EINTR);
- if (afd < 0)
+ if (NULL != hostname)
{
- return 0;
+ *hostname = NULL;
}
-#endif
+ *ip_address = NULL;
- /*
- * Determine the IP-Adress that the client used to reach us
- * and the hostname associated with that address
- */
if (!getsockname(afd, (struct sockaddr *) &server, &s_length))
{
- csp->my_ip_addr_str = strdup(inet_ntoa(server.sin_addr));
+ if (s_length > s_length_provided)
+ {
+ log_error(LOG_LEVEL_ERROR, "getsockname() truncated server address");
+ return;
+ }
+#ifdef HAVE_RFC2553
+ *ip_address = malloc(NI_MAXHOST);
+ retval = getnameinfo((struct sockaddr *) &server, s_length,
+ *ip_address, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
+ if (retval)
+ {
+ log_error(LOG_LEVEL_ERROR,
+ "Unable to print my own IP address: %s", gai_strerror(retval));
+ freez(*ip_address);
+ return;
+ }
+#else
+ *ip_address = strdup(inet_ntoa(server.sin_addr));
+#endif /* HAVE_RFC2553 */
+ if (NULL == hostname)
+ {
+ /*
+ * We're done here, the caller isn't
+ * interested in knowing the hostname.
+ */
+ return;
+ }
+
+#ifdef HAVE_RFC2553
+ *hostname = malloc(NI_MAXHOST);
+ retval = getnameinfo((struct sockaddr *) &server, s_length,
+ *hostname, NI_MAXHOST, NULL, 0, NI_NAMEREQD);
+ if (retval)
+ {
+ log_error(LOG_LEVEL_ERROR,
+ "Unable to resolve my own IP address: %s", gai_strerror(retval));
+ freez(*hostname);
+ }
+#else
#if defined(HAVE_GETHOSTBYADDR_R_8_ARGS)
gethostbyaddr_r((const char *)&server.sin_addr,
sizeof(server.sin_addr), AF_INET,
host = NULL;
}
#elif FEATURE_PTHREAD
- pthread_mutex_lock(&resolver_mutex);
+ privoxy_mutex_lock(&resolver_mutex);
host = gethostbyaddr((const char *)&server.sin_addr,
sizeof(server.sin_addr), AF_INET);
- pthread_mutex_unlock(&resolver_mutex);
+ privoxy_mutex_unlock(&resolver_mutex);
#else
host = gethostbyaddr((const char *)&server.sin_addr,
sizeof(server.sin_addr), AF_INET);
}
else
{
- csp->my_hostname = strdup(host->h_name);
+ *hostname = strdup(host->h_name);
}
+#endif /* else def HAVE_RFC2553 */
}
- csp->cfd = afd;
+ return;
+}
+
+
+/*********************************************************************
+ *
+ * Function : accept_connection
+ *
+ * Description : Accepts a connection on a socket. Socket must have
+ * been created using bind_port().
+ *
+ * Parameters :
+ * 1 : csp = Client state, cfd, ip_addr_str, and
+ * ip_addr_long will be set by this routine.
+ * 2 : fd = file descriptor returned from bind_port
+ *
+ * Returns : when a connection is accepted, it returns 1 (TRUE).
+ * On an error it returns 0 (FALSE).
+ *
+ *********************************************************************/
+int accept_connection(struct client_state * csp, jb_socket fd)
+{
+#ifdef HAVE_RFC2553
+ /* XXX: client is stored directly into csp->tcp_addr */
+#define client (csp->tcp_addr)
+ int retval;
+#else
+ struct sockaddr_in client;
+#endif
+ jb_socket afd;
+#if defined(_WIN32) || defined(__OS2__) || defined(__APPLE_CC__) || defined(AMIGA)
+ /* Wierdness - fix a warning. */
+ int c_length;
+#else
+ socklen_t c_length;
+#endif
+
+ c_length = sizeof(client);
+
+#ifdef _WIN32
+ afd = accept (fd, (struct sockaddr *) &client, &c_length);
+ if (afd == JB_INVALID_SOCKET)
+ {
+ return 0;
+ }
+#else
+ do
+ {
+ afd = accept (fd, (struct sockaddr *) &client, &c_length);
+ } while (afd < 1 && errno == EINTR);
+ if (afd < 0)
+ {
+ return 0;
+ }
+#endif
+
+ csp->cfd = afd;
+#ifdef HAVE_RFC2553
+ csp->ip_addr_str = malloc(NI_MAXHOST);
+ retval = getnameinfo((struct sockaddr *) &client, c_length,
+ csp->ip_addr_str, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
+ if (!csp->ip_addr_str || retval)
+ {
+ log_error(LOG_LEVEL_ERROR, "Can not save csp->ip_addr_str: %s",
+ (csp->ip_addr_str) ? gai_strerror(retval) : "Insuffcient memory");
+ freez(csp->ip_addr_str);
+ }
+#undef client
+#else
csp->ip_addr_str = strdup(inet_ntoa(client.sin_addr));
csp->ip_addr_long = ntohl(client.sin_addr.s_addr);
+#endif /* def HAVE_RFC2553 */
return 1;
hostp = NULL;
}
#elif FEATURE_PTHREAD
- pthread_mutex_lock(&resolver_mutex);
+ privoxy_mutex_lock(&resolver_mutex);
while (NULL == (hostp = gethostbyname(host))
&& (h_errno == TRY_AGAIN) && (dns_retries++ < MAX_DNS_RETRIES))
{
"Timeout #%u while trying to resolve %s. Trying again.",
dns_retries, host);
}
- pthread_mutex_unlock(&resolver_mutex);
+ privoxy_mutex_unlock(&resolver_mutex);
#else
while (NULL == (hostp = gethostbyname(host))
&& (h_errno == TRY_AGAIN) && (dns_retries++ < MAX_DNS_RETRIES))
}
+#ifdef FEATURE_CONNECTION_KEEP_ALIVE
+/*********************************************************************
+ *
+ * Function : socket_is_still_usable
+ *
+ * Description : Decides whether or not an open socket is still usable.
+ *
+ * Parameters :
+ * 1 : sfd = The socket to check.
+ *
+ * Returns : TRUE for yes, otherwise FALSE.
+ *
+ *********************************************************************/
+int socket_is_still_usable(jb_socket sfd)
+{
+#ifdef HAVE_POLL
+ int poll_result;
+ struct pollfd poll_fd[1];
+
+ memset(poll_fd, 0, sizeof(poll_fd));
+ poll_fd[0].fd = sfd;
+ poll_fd[0].events = POLLIN;
+
+ poll_result = poll(poll_fd, 1, 0);
+
+ if (-1 != poll_result)
+ {
+ return !(poll_fd[0].revents & POLLIN);
+ }
+ else
+ {
+ log_error(LOG_LEVEL_CONNECT, "Polling socket %d failed.", sfd);
+ return FALSE;
+ }
+#else
+ fd_set readable_fds;
+ struct timeval timeout;
+ int ret;
+ int socket_is_alive = 0;
+
+ memset(&timeout, '\0', sizeof(timeout));
+ FD_ZERO(&readable_fds);
+ FD_SET(sfd, &readable_fds);
+
+ ret = select((int)sfd+1, &readable_fds, NULL, NULL, &timeout);
+ if (ret < 0)
+ {
+ log_error(LOG_LEVEL_ERROR, "select() failed!: %E");
+ }
+
+ /*
+ * XXX: I'm not sure why !FD_ISSET() works,
+ * but apparently it does.
+ */
+ socket_is_alive = !FD_ISSET(sfd, &readable_fds);
+
+ return socket_is_alive;
+#endif /* def HAVE_POLL */
+}
+#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
+
+
/*
Local Variables:
tab-width: 3