-const char cgi_rcs[] = "$Id: cgi.c,v 1.139 2011/07/08 13:27:56 fabiankeil Exp $";
+const char cgi_rcs[] = "$Id: cgi.c,v 1.140 2011/07/08 13:28:11 fabiankeil Exp $";
/*********************************************************************
*
* File : $Source: /cvsroot/ijbswa/current/cgi.c,v $
struct map * exports;
int local_help_exists = 0;
char *ip_address = NULL;
+ char *port = NULL;
char *hostname = NULL;
assert(csp);
if (csp->config->hostname)
{
- get_host_information(csp->cfd, &ip_address, NULL);
+ get_host_information(csp->cfd, &ip_address, &port, NULL);
hostname = strdup(csp->config->hostname);
}
else
{
- get_host_information(csp->cfd, &ip_address, &hostname);
+ get_host_information(csp->cfd, &ip_address, &port, &hostname);
}
err = map(exports, "version", 1, html_encode(VERSION), 0);
if (!err) err = map(exports, "time", 1, html_encode(buf), 0);
if (!err) err = map(exports, "my-ip-address", 1, html_encode(ip_address ? ip_address : "unknown"), 0);
freez(ip_address);
+ if (!err) err = map(exports, "my-port", 1, html_encode(port ? port : "unkown"), 0);
+ freez(port);
if (!err) err = map(exports, "my-hostname", 1, html_encode(hostname ? hostname : "unknown"), 0);
freez(hostname);
if (!err) err = map(exports, "homepage", 1, html_encode(HOME_PAGE_URL), 0);
if (!err) err = map_block_killer(exports, "can-toggle");
#endif
- snprintf(buf, sizeof(buf), "%d", csp->config->hport);
- if (!err) err = map(exports, "my-port", 1, buf, 1);
-
if(!strcmp(CODE_STATUS, "stable"))
{
if (!err) err = map_block_killer(exports, "unstable");
Purpose : Used with other docs and files only.
- $Id: p-config.sgml,v 2.74 2011/07/08 13:31:17 fabiankeil Exp $
+ $Id: p-config.sgml,v 2.75 2011/07/08 13:31:40 fabiankeil Exp $
Copyright (C) 2001-2010 Privoxy Developers http://www.privoxy.org/
See LICENSE.
Sample Configuration File for Privoxy v&p-version;
</title>
<para>
- $Id: p-config.sgml,v 2.74 2011/07/08 13:31:17 fabiankeil Exp $
+ $Id: p-config.sgml,v 2.75 2011/07/08 13:31:40 fabiankeil Exp $
</para>
<para>
Copyright (C) 2001-2010 Privoxy Developers http://www.privoxy.org/
serve requests from other machines (e.g. on your local network) as well, you
will need to override the default.
</para>
+ <para>
+ You can use this statement multiple times to make
+ <application>Privoxy</application> listen on more ports or more
+ <abbrev>IP</abbrev> addresses. Suitable if your operating system does not
+ support sharing <abbrev>IPv6</abbrev> and <abbrev>IPv4</abbrev> protocols
+ on the same socket.
+ </para>
<para>
If a hostname is used instead of an IP address, <application>Privoxy</application>
will try to resolve it to an IP address and if there are multiple, use the first
-const char jbsockets_rcs[] = "$Id: jbsockets.c,v 1.103 2011/06/23 13:58:22 fabiankeil Exp $";
+const char jbsockets_rcs[] = "$Id: jbsockets.c,v 1.104 2011/07/04 17:47:29 fabiankeil Exp $";
/*********************************************************************
*
* File : $Source: /cvsroot/ijbswa/current/jbsockets.c,v $
* 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
+ * 3 : port = Pointer to return the pointer to
+ * the TCP port string.
+ * 4 : hostname = Pointer to return the pointer to
* the hostname or NULL if the caller
* isn't interested in it.
*
* Returns : void.
*
*********************************************************************/
-void get_host_information(jb_socket afd, char **ip_address, char **hostname)
+void get_host_information(jb_socket afd, char **ip_address, char **port,
+ char **hostname)
{
#ifdef HAVE_RFC2553
struct sockaddr_storage server;
*hostname = NULL;
}
*ip_address = NULL;
+ *port = NULL;
if (!getsockname(afd, (struct sockaddr *) &server, &s_length))
{
log_error(LOG_LEVEL_ERROR, "getsockname() truncated server address");
return;
}
+ *port = malloc(NI_MAXSERV);
+ if (NULL == *port)
+ {
+ log_error(LOG_LEVEL_ERROR,
+ "Out of memory while getting the client's port.");
+ return;
+ }
#ifdef HAVE_RFC2553
*ip_address = malloc(NI_MAXHOST);
if (NULL == *ip_address)
{
log_error(LOG_LEVEL_ERROR,
"Out of memory while getting the client's IP address.");
+ freez(*port);
return;
}
retval = getnameinfo((struct sockaddr *) &server, s_length,
- *ip_address, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
+ *ip_address, NI_MAXHOST, *port, NI_MAXSERV,
+ NI_NUMERICHOST|NI_NUMERICSERV);
if (retval)
{
log_error(LOG_LEVEL_ERROR,
"Unable to print my own IP address: %s", gai_strerror(retval));
freez(*ip_address);
+ freez(*port);
return;
}
#else
*ip_address = strdup(inet_ntoa(server.sin_addr));
+ snprintf(*port, NI_MAXSERV, "%hu", ntohs(server.sin_port));
+ *port[NI_MAXSERV - 1] = '\0';
#endif /* HAVE_RFC2553 */
if (NULL == hostname)
{
*
* Function : accept_connection
*
- * Description : Accepts a connection on a socket. Socket must have
- * been created using bind_port().
+ * Description : Accepts a connection on one of more socket. Sockets
+ * 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
+ * 2 : fds = File descriptors 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)
+int accept_connection(struct client_state * csp, jb_socket fds[])
{
#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
#else
socklen_t c_length;
#endif
+ int retval;
+ int i;
+ int max_selected_socket;
+ fd_set selected_fds;
+ jb_socket fd;
c_length = sizeof(client);
+ /* Wait for a connection on any socket. Return immediately if no socket is
+ * listening. */
+ FD_ZERO(&selected_fds);
+ max_selected_socket = 0;
+ for (i = 0; i < MAX_LISTENING_SOCKETS; i++)
+ {
+ if (JB_INVALID_SOCKET != fds[i])
+ {
+ FD_SET(fds[i], &selected_fds);
+ if (max_selected_socket < fds[i] + 1)
+ {
+ max_selected_socket = fds[i] + 1;
+ }
+ }
+ }
+ if (0 == max_selected_socket)
+ {
+ return 0;
+ }
+ do
+ {
+ retval = select(max_selected_socket, &selected_fds, NULL, NULL, NULL);
+ } while (retval < 0 && errno == EINTR);
+ if (retval <= 0)
+ {
+ if (0 == retval)
+ {
+ log_error(LOG_LEVEL_ERROR,
+ "Waiting on new client failed because select(2) returned 0."
+ " This should not happen.");
+ }
+ else
+ {
+ log_error(LOG_LEVEL_ERROR,
+ "Waiting on new client failed because of problems in select(2): "
+ "%s.", strerror(errno));
+ }
+ return 0;
+ }
+ for (i = 0; i < MAX_LISTENING_SOCKETS && !FD_ISSET(fds[i], &selected_fds);
+ i++);
+ if (i >= MAX_LISTENING_SOCKETS)
+ {
+ log_error(LOG_LEVEL_ERROR,
+ "select(2) reported connected clients (number = %u, "
+ "descriptor boundary = %u), but none found.",
+ retval, max_selected_socket);
+ return 0;
+ }
+ fd = fds[i];
+
+ /* Accept selected connection */
#ifdef _WIN32
afd = accept (fd, (struct sockaddr *) &client, &c_length);
if (afd == JB_INVALID_SOCKET)
#ifndef JBSOCKETS_H_INCLUDED
#define JBSOCKETS_H_INCLUDED
-#define JBSOCKETS_H_VERSION "$Id: jbsockets.h,v 1.16 2009/05/16 13:27:20 fabiankeil Exp $"
+#define JBSOCKETS_H_VERSION "$Id: jbsockets.h,v 1.17 2010/04/23 11:53:48 fabiankeil Exp $"
/*********************************************************************
*
* File : $Source: /cvsroot/ijbswa/current/jbsockets.h,v $
extern void close_socket(jb_socket fd);
extern int bind_port(const char *hostnam, int portnum, jb_socket *pfd);
-extern int accept_connection(struct client_state * csp, jb_socket fd);
-extern void get_host_information(jb_socket afd, char **ip_address, char **hostname);
+extern int accept_connection(struct client_state * csp, jb_socket fds[]);
+extern void get_host_information(jb_socket afd, char **ip_address, char **port, char **hostname);
extern unsigned long resolve_hostname_to_ip(const char *host);
-const char jcc_rcs[] = "$Id: jcc.c,v 1.356 2011/07/17 13:30:24 fabiankeil Exp $";
+const char jcc_rcs[] = "$Id: jcc.c,v 1.357 2011/07/17 13:31:02 fabiankeil Exp $";
/*********************************************************************
*
* File : $Source: /cvsroot/ijbswa/current/jcc.c,v $
static void usage(const char *myname);
#endif
static void initialize_mutexes(void);
-static jb_socket bind_port_helper(struct configuration_spec *config);
+static jb_socket bind_port_helper(const char *haddr, int hport);
+static void bind_ports_helper(struct configuration_spec *config, jb_socket sockets[]);
+static void close_ports_helper(jb_socket sockets[]);
static void listen_loop(void);
#ifdef AMIGA
* on failure.
*
* Parameters :
- * 1 : config = Privoxy configuration. Specifies port
- * to bind to.
+ * 1 : haddr = Host addres to bind to. Use NULL to bind to
+ * INADDR_ANY.
+ * 2 : hport = Specifies port to bind to.
*
* Returns : Port that was opened.
*
*********************************************************************/
-static jb_socket bind_port_helper(struct configuration_spec * config)
+static jb_socket bind_port_helper(const char *haddr, int hport)
{
int result;
jb_socket bfd;
- if (config->haddr == NULL)
+ if (haddr == NULL)
{
log_error(LOG_LEVEL_INFO, "Listening on port %d on all IP addresses",
- config->hport);
+ hport);
}
else
{
log_error(LOG_LEVEL_INFO, "Listening on port %d on IP address %s",
- config->hport, config->haddr);
+ hport, haddr);
}
- result = bind_port(config->haddr, config->hport, &bfd);
+ result = bind_port(haddr, hport, &bfd);
if (result < 0)
{
log_error(LOG_LEVEL_FATAL, "can't bind to %s:%d: "
"There may be another Privoxy or some other "
"proxy running on port %d",
- (NULL != config->haddr) ? config->haddr : "INADDR_ANY",
- config->hport, config->hport);
+ (NULL != haddr) ? haddr : "INADDR_ANY", hport, hport);
case -2 :
log_error(LOG_LEVEL_FATAL, "can't bind to %s:%d: "
"The hostname is not resolvable",
- (NULL != config->haddr) ? config->haddr : "INADDR_ANY", config->hport);
+ (NULL != haddr) ? haddr : "INADDR_ANY", hport);
default :
log_error(LOG_LEVEL_FATAL, "can't bind to %s:%d: %E",
- (NULL != config->haddr) ? config->haddr : "INADDR_ANY", config->hport);
+ (NULL != haddr) ? haddr : "INADDR_ANY", hport);
}
/* shouldn't get here */
return JB_INVALID_SOCKET;
}
- config->need_bind = 0;
-
return bfd;
}
+/*********************************************************************
+ *
+ * Function : bind_ports_helper
+ *
+ * Description : Bind the listen ports. Handles logging, and aborts
+ * on failure.
+ *
+ * Parameters :
+ * 1 : config = Privoxy configuration. Specifies ports
+ * to bind to.
+ * 2 : sockets = Preallocated array of opened sockets
+ * corresponding to specification in config.
+ * All non-opened sockets will be set to
+ * JB_INVALID_SOCKET.
+ *
+ * Returns : Nothing. Inspect sockets argument.
+ *
+ *********************************************************************/
+static void bind_ports_helper(struct configuration_spec * config,
+ jb_socket sockets[])
+{
+ int i;
+
+ config->need_bind = 1;
+
+ for (i = 0; i < MAX_LISTENING_SOCKETS; i++)
+ {
+ sockets[i] = JB_INVALID_SOCKET;
+
+ if (config->hport[i])
+ {
+ sockets[i] = bind_port_helper(config->haddr[i], config->hport[i]);
+ if (JB_INVALID_SOCKET != sockets[i])
+ {
+ config->need_bind = 0;
+ }
+ }
+ }
+}
+
+
+/*********************************************************************
+ *
+ * Function : close_ports_helper
+ *
+ * Description : Close listenings ports.
+ *
+ * Parameters :
+ * 1 : sockets = Array of opened and non-opened sockets to
+ * close. All sockets will be set to
+ * JB_INVALID_SOCKET.
+ *
+ * Returns : Nothing.
+ *
+ *********************************************************************/
+static void close_ports_helper(jb_socket sockets[])
+{
+ int i;
+
+ for (i = 0; i < MAX_LISTENING_SOCKETS; i++)
+ {
+ if (JB_INVALID_SOCKET != sockets[i])
+ {
+ close_socket(sockets[i]);
+ }
+ sockets[i] = JB_INVALID_SOCKET;
+ }
+}
+
+
#ifdef _WIN32
/* Without this simple workaround we get this compiler warning from _beginthread
* warning C4028: formal parameter 1 different from declaration
{
struct client_states *csp_list = NULL;
struct client_state *csp = NULL;
- jb_socket bfd;
+ jb_socket bfds[MAX_LISTENING_SOCKETS];
struct configuration_spec *config;
unsigned int active_threads = 0;
initialize_reusable_connections();
#endif /* def FEATURE_CONNECTION_SHARING */
- bfd = bind_port_helper(config);
+ bind_ports_helper(config, bfds);
#ifdef FEATURE_GRACEFUL_TERMINATION
while (!g_terminate)
log_error(LOG_LEVEL_CONNECT, "Listening for new connections ... ");
- if (!accept_connection(csp, bfd))
+ if (!accept_connection(csp, bfds))
{
log_error(LOG_LEVEL_CONNECT, "accept failed: %E");
* that this will hurt people's feelings.
*/
- close_socket(bfd);
+ close_ports_helper(bfds);
- bfd = bind_port_helper(config);
+ bind_ports_helper(config, bfds);
}
#ifdef FEATURE_TOGGLE
-const char loadcfg_rcs[] = "$Id: loadcfg.c,v 1.116 2011/07/08 13:29:39 fabiankeil Exp $";
+const char loadcfg_rcs[] = "$Id: loadcfg.c,v 1.117 2011/07/08 13:30:08 fabiankeil Exp $";
/*********************************************************************
*
* File : $Source: /cvsroot/ijbswa/current/loadcfg.c,v $
freez(config->templdir);
freez(config->hostname);
- freez(config->haddr);
+ for (i = 0; i < MAX_LISTENING_SOCKETS; i++)
+ {
+ freez(config->haddr[i]);
+ }
freez(config->logfile);
for (i = 0; i < MAX_AF_FILES; i++)
* listen-address [ip][:port]
* *************************************************************************/
case hash_listen_address :
- freez(config->haddr);
- config->haddr = strdup(arg);
+ i = 0;
+ while ((i < MAX_LISTENING_SOCKETS) && (NULL != config->haddr[i]))
+ {
+ i++;
+ }
+
+ if (i >= MAX_LISTENING_SOCKETS)
+ {
+ log_error(LOG_LEVEL_FATAL, "Too many 'listen-address' directives in config file - limit is %d.\n"
+ "(You can increase this limit by changing MAX_LISTENING_SOCKETS in project.h and recompiling).",
+ MAX_LISTENING_SOCKETS);
+ }
+ config->haddr[i] = strdup(arg);
+ if (NULL == config->haddr[i])
+ {
+ log_error(LOG_LEVEL_FATAL, "Out of memory while copying listening address");
+ }
break;
/* *************************************************************************
}
#endif /* def FEATURE_TRUST */
- if ( NULL == config->haddr )
+ if ( NULL == config->haddr[0] )
{
- config->haddr = strdup( HADDR_DEFAULT );
+ config->haddr[0] = strdup( HADDR_DEFAULT );
+ if (NULL == config->haddr[0])
+ {
+ log_error(LOG_LEVEL_FATAL, "Out of memory while copying default listening address");
+ }
}
- if ( NULL != config->haddr )
+ for (i = 0; i < MAX_LISTENING_SOCKETS && NULL != config->haddr[i]; i++ )
{
- if ((*config->haddr == '[')
- && (NULL != (p = strchr(config->haddr, ']')))
+ if ((*config->haddr[i] == '[')
+ && (NULL != (p = strchr(config->haddr[i], ']')))
&& (p[1] == ':')
- && (0 < (config->hport = atoi(p + 2))))
+ && (0 < (config->hport[i] = atoi(p + 2))))
{
*p = '\0';
- memmove((void *)config->haddr, config->haddr + 1,
- (size_t)(p - config->haddr));
+ memmove((void *)config->haddr[i], config->haddr[i] + 1,
+ (size_t)(p - config->haddr[i]));
}
- else if (NULL != (p = strchr(config->haddr, ':'))
- && (0 < (config->hport = atoi(p + 1))))
+ else if (NULL != (p = strchr(config->haddr[i], ':'))
+ && (0 < (config->hport[i] = atoi(p + 1))))
{
*p = '\0';
}
else
{
- log_error(LOG_LEVEL_FATAL, "invalid bind port spec %s", config->haddr);
+ log_error(LOG_LEVEL_FATAL, "invalid bind port spec %s", config->haddr[i]);
/* Never get here - LOG_LEVEL_FATAL causes program exit */
}
- if (*config->haddr == '\0')
+ if (*config->haddr[i] == '\0')
{
/*
- * Only the port specified. We stored it in config->hport
+ * Only the port specified. We stored it in config->hport[i]
* and don't need its text representation anymore.
+ * Use config->hport[i] == 0 to iterate listening addresses since
+ * now.
*/
- freez(config->haddr);
+ freez(config->haddr[i]);
}
}
struct configuration_spec * oldcfg = (struct configuration_spec *)
current_configfile->f;
/*
- * Check if config->haddr,hport == oldcfg->haddr,hport
+ * Check if config->haddr[i],hport[i] == oldcfg->haddr[i],hport[i]
*
* The following could be written more compactly as a single,
* (unreadably long) if statement.
*/
config->need_bind = 0;
- if (config->hport != oldcfg->hport)
- {
- config->need_bind = 1;
- }
- else if (config->haddr == NULL)
+
+ for (i = 0; i < MAX_LISTENING_SOCKETS; i++)
{
- if (oldcfg->haddr != NULL)
+ if (config->hport[i] != oldcfg->hport[i])
+ {
+ config->need_bind = 1;
+ }
+ else if (config->haddr[i] == NULL)
+ {
+ if (oldcfg->haddr[i] != NULL)
+ {
+ config->need_bind = 1;
+ }
+ }
+ else if (oldcfg->haddr[i] == NULL)
+ {
+ config->need_bind = 1;
+ }
+ else if (0 != strcmp(config->haddr[i], oldcfg->haddr[i]))
{
config->need_bind = 1;
}
- }
- else if (oldcfg->haddr == NULL)
- {
- config->need_bind = 1;
- }
- else if (0 != strcmp(config->haddr, oldcfg->haddr))
- {
- config->need_bind = 1;
}
current_configfile->unloader = unload_configfile;
#ifndef PROJECT_H_INCLUDED
#define PROJECT_H_INCLUDED
/** Version string. */
-#define PROJECT_H_VERSION "$Id: project.h,v 1.168 2011/07/08 13:27:31 fabiankeil Exp $"
+#define PROJECT_H_VERSION "$Id: project.h,v 1.169 2011/07/08 13:30:08 fabiankeil Exp $"
/*********************************************************************
*
* File : $Source: /cvsroot/ijbswa/current/project.h,v $
*/
#define MAX_AF_FILES 10
+/**
+ * Maximum number of sockets to listen to. This limit is arbitrary - it's just used
+ * to size an array.
+ */
+#define MAX_LISTENING_SOCKETS 10
+
/**
* The state of a Privoxy processing thread.
*/
/** The hostname to show on CGI pages, or NULL to use the real one. */
const char *hostname;
- /** IP address to bind to. Defaults to HADDR_DEFAULT == 127.0.0.1. */
- const char *haddr;
+ /** IP addresses to bind to. Defaults to HADDR_DEFAULT == 127.0.0.1. */
+ const char *haddr[MAX_LISTENING_SOCKETS];
- /** Port to bind to. Defaults to HADDR_PORT == 8118. */
- int hport;
+ /** Ports to bind to. Defaults to HADDR_PORT == 8118. */
+ int hport[MAX_LISTENING_SOCKETS];
/** Size limit for IOB */
size_t buffer_limit;