-const char jbsockets_rcs[] = "$Id: jbsockets.c,v 1.50 2008/12/20 14:53:55 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
#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;
* file descriptor.
*
*********************************************************************/
-#ifdef HAVE_GETADDRINFO
+#ifdef HAVE_RFC2553
/* Getaddrinfo implementation */
jb_socket connect_to(const char *host, int portnum, struct client_state *csp)
{
#endif /* def FEATURE_ACL */
retval = snprintf(service, sizeof(service), "%d", portnum);
- if (-1 == retval || sizeof(service) <= retval)
+ if ((-1 == retval) || (sizeof(service) <= retval))
{
log_error(LOG_LEVEL_ERROR,
- "Port number (%d) ASCII decimal representation doesn't fit into 6 bytes",
- portnum);
+ "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);
+ 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));
+ "Can not resolve %s: %s", host, gai_strerror(retval));
csp->http->host_ip_addr_str = strdup("unknown");
return(JB_INVALID_SOCKET);
}
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);
+ 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");
+ 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 (errno == WSAEINPROGRESS)
-#elif __OS2__
+#elif __OS2__
if (sock_errno() == EINPROGRESS)
#else /* ifndef _WIN32 */
if (errno == EINPROGRESS)
break;
}
-#ifdef __OS2__
+#ifdef __OS2__
if (sock_errno() != EINTR)
#else
if (errno != EINTR)
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);
+ 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 my 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 not log here the socket is connected. */
- /*log_error(LOG_LEVEL_INFO, "Connected to TCP/[%s]:%s", host, service);*/
+ /*
+ * 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_GETADDRINFO */
+#else /* ndef HAVE_RFC2553 */
/* Pre-getaddrinfo implementation */
jb_socket connect_to(const char *host, int portnum, struct client_state *csp)
return(fd);
}
-#endif /* ndef HAVE_GETADDRINFO */
+#endif /* ndef HAVE_RFC2553 */
/*********************************************************************
*********************************************************************/
int bind_port(const char *hostnam, int portnum, jb_socket *pfd)
{
-#ifdef HAVE_GETADDRINFO
+#ifdef HAVE_RFC2553
struct addrinfo hints;
struct addrinfo *result, *rp;
- /* TODO: portnum shuld be string to allow symbolic service names in
- * configuration and to avoid following int2string */
+ /*
+ * 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_GETADDRINFO */
+#endif /* def HAVE_RFC2553 */
jb_socket fd;
#ifndef _WIN32
int one = 1;
*pfd = JB_INVALID_SOCKET;
-#ifdef HAVE_GETADDRINFO
+#ifdef HAVE_RFC2553
retval = snprintf(servnam, sizeof(servnam), "%d", portnum);
- if (-1 == retval || sizeof(servnam) <= retval)
+ if ((-1 == retval) || (sizeof(servnam) <= retval))
{
log_error(LOG_LEVEL_ERROR,
- "Port number (%d) ASCII decimal representation doesn't fit into 6 bytes",
- portnum);
+ "Port number (%d) ASCII decimal representation doesn't fit into 6 bytes",
+ portnum);
return -1;
}
memset(&hints, 0, sizeof(struct addrinfo));
- 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 ((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));
+ "Can not resolve %s: %s", hostnam, gai_strerror(retval));
return -2;
}
#else
inaddr.sin_port = htonl((unsigned long) portnum);
}
#endif /* ndef _WIN32 */
-#endif /* def HAVE_GETADDRINFO */
+#endif /* def HAVE_RFC2553 */
-#ifdef HAVE_GETADDRINFO
+#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_GETADDRINFO */
+#endif /* def HAVE_RFC2553 */
#ifdef _WIN32
if (fd == JB_INVALID_SOCKET)
if (fd < 0)
#endif
{
-#ifdef HAVE_GETADDRINFO
+#ifdef HAVE_RFC2553
continue;
#else
return(-1);
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one));
#endif /* ndef _WIN32 */
-#ifdef HAVE_GETADDRINFO
+#ifdef HAVE_RFC2553
if (bind(fd, rp->ai_addr, rp->ai_addrlen) < 0)
#else
if (bind(fd, (struct sockaddr *)&inaddr, sizeof(inaddr)) < 0)
if (errno == EADDRINUSE)
#endif
{
-#ifdef HAVE_GETADDRINFO
+#ifdef HAVE_RFC2553
freeaddrinfo(result);
#endif
close_socket(fd);
else
{
close_socket(fd);
-#ifndef HAVE_GETADDRINFO
+#ifndef HAVE_RFC2553
return(-1);
}
}
}
}
else
+ {
/* bind() succeeded, escape from for-loop */
- /* TODO: Support multiple listening sockets (e.g. localhost resolves to
- * AF_INET and AF_INET6, but only fist address is used */
+ /*
+ * 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_GETADDRINFO */
+#endif /* ndef HAVE_RFC2553 */
while (listen(fd, MAX_LISTEN_BACKLOG) == -1)
{
*********************************************************************/
void get_host_information(jb_socket afd, char **ip_address, char **hostname)
{
-#ifdef HAVE_GETNAMEINFO
+#ifdef HAVE_RFC2553
struct sockaddr_storage server;
int retval;
#else
struct sockaddr_in server;
struct hostent *host = NULL;
-#endif /* HAVE_GETNAMEINFO */
+#endif /* HAVE_RFC2553 */
#if defined(_WIN32) || defined(__OS2__) || defined(__APPLE_CC__) || defined(AMIGA)
/* according to accept_connection() this fixes a warning. */
int s_length, s_length_provided;
#else
socklen_t s_length, s_length_provided;
#endif
-#ifndef HAVE_GETNAMEINFO
+#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_GETNAMEINFO */
+#endif /* ifndef HAVE_RFC2553 */
s_length = s_length_provided = sizeof(server);
if (NULL != hostname)
log_error(LOG_LEVEL_ERROR, "getsockname() truncated server address");
return;
}
-#ifdef HAVE_GETNAMEINFO
+#ifdef HAVE_RFC2553
*ip_address = malloc(NI_MAXHOST);
- if ((retval = getnameinfo((struct sockaddr *) &server, s_length,
- *ip_address, NI_MAXHOST, NULL, 0, NI_NUMERICHOST))) {
- log_error(LOG_LEVEL_ERROR, "Unable to print my own IP address: %s",
- gai_strerror(retval));
+ 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_GETNAMEINFO */
+#endif /* HAVE_RFC2553 */
if (NULL == hostname)
{
/*
return;
}
-#ifdef HAVE_GETNAMEINFO
+#ifdef HAVE_RFC2553
*hostname = malloc(NI_MAXHOST);
- if ((retval = getnameinfo((struct sockaddr *) &server, s_length,
- *hostname, NI_MAXHOST, NULL, 0, NI_NAMEREQD))) {
- log_error(LOG_LEVEL_ERROR, "Unable to resolve my own IP address: %s",
- gai_strerror(retval));
+ 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
{
*hostname = strdup(host->h_name);
}
-#endif /* else def HAVE_GETNAMEINFO */
+#endif /* else def HAVE_RFC2553 */
}
return;
*********************************************************************/
int accept_connection(struct client_state * csp, jb_socket fd)
{
-#ifdef HAVE_GETNAMEINFO
+#ifdef HAVE_RFC2553
/* XXX: client is stored directly into csp->tcp_addr */
#define client (csp->tcp_addr)
int retval;
#endif
csp->cfd = afd;
-#ifdef HAVE_GETNAMEINFO
+#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);
#else
csp->ip_addr_str = strdup(inet_ntoa(client.sin_addr));
csp->ip_addr_long = ntohl(client.sin_addr.s_addr);
-#endif /* def HAVE_GETNAMEINFO */
+#endif /* def HAVE_RFC2553 */
return 1;
}
+#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
end:
-
- vim:softtabstop=3 shiftwidth=3
*/