-const char jbsockets_rcs[] = "$Id: jbsockets.c,v 1.123 2013/03/06 21:06:18 diem Exp $";
+const char jbsockets_rcs[] = "$Id: jbsockets.c,v 1.135 2016/01/16 12:33:35 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-2011 the
+ * Copyright : Written by and Copyright (C) 2001-2016 the
* Privoxy team. http://www.privoxy.org/
*
* Based on the Internet Junkbuster originally written
#include "jbsockets.h"
#include "filters.h"
#include "errlog.h"
+#include "miscutil.h"
/* Mac OSX doesn't define AI_NUMERICSESRV */
#ifndef AI_NUMERICSERV
static jb_socket no_rfc2553_connect_to(const char *host, int portnum, struct client_state *csp);
#endif
+/*********************************************************************
+ *
+ * Function : set_no_delay_flag
+ *
+ * Description : Disables TCP coalescence for the given socket.
+ *
+ * Parameters :
+ * 1 : fd = The file descriptor to operate on
+ *
+ * Returns : void
+ *
+ *********************************************************************/
+static void set_no_delay_flag(int fd)
+{
+#ifdef TCP_NODELAY
+ int mi = 1;
+
+ if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &mi, sizeof(int)))
+ {
+ log_error(LOG_LEVEL_ERROR,
+ "Failed to disable TCP coalescence for socket %d", fd);
+ }
+#else
+#warning set_no_delay_flag() is a nop due to lack of TCP_NODELAY
+#endif /* def TCP_NODELAY */
+}
+
/*********************************************************************
*
* Function : connect_to
return(JB_INVALID_SOCKET);
}
- csp->http->host_ip_addr_str = malloc(NI_MAXHOST);
- if (NULL == csp->http->host_ip_addr_str)
- {
- freeaddrinfo(result);
- log_error(LOG_LEVEL_ERROR,
- "Out of memory while getting the server IP address.");
- return JB_INVALID_SOCKET;
- }
+ csp->http->host_ip_addr_str = malloc_or_die(NI_MAXHOST);
for (rp = result; rp != NULL; rp = rp->ai_next)
{
"Server socket number too high to use select(): %d >= %d",
fd, FD_SETSIZE);
close_socket(fd);
+ freeaddrinfo(result);
return JB_INVALID_SOCKET;
}
#endif
-#ifdef TCP_NODELAY
- { /* turn off TCP coalescence */
- int mi = 1;
- setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &mi, sizeof (int));
- }
-#endif /* def TCP_NODELAY */
+#ifdef FEATURE_EXTERNAL_FILTERS
+ mark_socket_for_close_on_execute(fd);
+#endif
+
+ set_no_delay_flag(fd);
#if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__)
if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
}
#endif
-#ifdef TCP_NODELAY
- { /* turn off TCP coalescence */
- int mi = 1;
- setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &mi, sizeof (int));
- }
-#endif /* def TCP_NODELAY */
+ set_no_delay_flag(fd);
#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);
+#ifdef FEATURE_EXTERNAL_FILTERS
+ mark_socket_for_close_on_execute(fd);
+#endif
}
#endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) */
#endif
}
+#ifdef FEATURE_EXTERNAL_FILTERS
+ mark_socket_for_close_on_execute(fd);
+#endif
+
#ifndef _WIN32
/*
* This is not needed for Win32 - in fact, it stops
{
if (errno != EINTR)
{
+ close_socket(fd);
return(-1);
}
}
#ifndef NI_MAXSERV
#define NI_MAXSERV 32
#endif
- *port = malloc(NI_MAXSERV);
- if (NULL == *port)
- {
- log_error(LOG_LEVEL_ERROR,
- "Out of memory while getting the client's port.");
- return;
- }
+ *port = malloc_or_die(NI_MAXSERV);
+
#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;
- }
+ *ip_address = malloc_or_die(NI_MAXHOST);
retval = getnameinfo((struct sockaddr *) &server, s_length,
*ip_address, NI_MAXHOST, *port, NI_MAXSERV,
NI_NUMERICHOST|NI_NUMERICSERV);
}
#ifdef HAVE_RFC2553
- *hostname = malloc(NI_MAXHOST);
- if (NULL == *hostname)
- {
- log_error(LOG_LEVEL_ERROR,
- "Out of memory while getting the client's hostname.");
- return;
- }
+ *hostname = malloc_or_die(NI_MAXHOST);
retval = getnameinfo((struct sockaddr *) &server, s_length,
*hostname, NI_MAXHOST, NULL, 0, NI_NAMEREQD);
if (retval)
int max_selected_socket;
fd_set selected_fds;
jb_socket fd;
+ size_t listen_addr_size;
c_length = sizeof(client);
setsockopt(fd, SOL_SOCKET, SO_ACCEPTFILTER, &af_options, sizeof(af_options));
#endif
afd = accept (fd, (struct sockaddr *) &client, &c_length);
- } while (afd < 1 && errno == EINTR);
+ } while (afd < 0 && errno == EINTR);
if (afd < 0)
{
return 0;
struct linger linger_options;
linger_options.l_onoff = 1;
linger_options.l_linger = 5;
- if (0 != setsockopt(fd, SOL_SOCKET, SO_LINGER, &linger_options, sizeof(linger_options)))
+ if (0 != setsockopt(afd, SOL_SOCKET, SO_LINGER, &linger_options, sizeof(linger_options)))
{
log_error(LOG_LEVEL_ERROR, "Setting SO_LINGER on socket %d failed.", afd);
}
}
#endif
+#ifdef FEATURE_EXTERNAL_FILTERS
+ mark_socket_for_close_on_execute(afd);
+#endif
+
+ set_no_delay_flag(afd);
+
csp->cfd = afd;
#ifdef HAVE_RFC2553
- csp->ip_addr_str = malloc(NI_MAXHOST);
- if (NULL == csp->ip_addr_str)
- {
- log_error(LOG_LEVEL_ERROR,
- "Out of memory while getting the client's IP address.");
- return 0;
- }
+ csp->ip_addr_str = malloc_or_die(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)
csp->ip_addr_long = ntohl(client.sin_addr.s_addr);
#endif /* def HAVE_RFC2553 */
+ /*
+ * Save the name and port of the accepting socket for later lookup.
+ *
+ * The string needs space for strlen(...) + 7 characters:
+ * strlen(haddr[i]) + 1 (':') + 5 (port digits) + 1 ('\0')
+ */
+ listen_addr_size = strlen(csp->config->haddr[i]) + 7;
+ csp->listen_addr_str = malloc_or_die(listen_addr_size);
+ retval = snprintf(csp->listen_addr_str, listen_addr_size,
+ "%s:%d", csp->config->haddr[i], csp->config->hport[i]);
+ if ((-1 == retval) || listen_addr_size <= retval)
+ {
+ log_error(LOG_LEVEL_ERROR,
+ "Server name (%s) and port number (%d) ASCII decimal representation"
+ "don't fit into %d bytes",
+ csp->config->haddr[i], csp->config->hport[i], listen_addr_size);
+ return 0;
+ }
+
return 1;
}
}
+#ifdef FEATURE_EXTERNAL_FILTERS
+/*********************************************************************
+ *
+ * Function : mark_socket_for_close_on_execute
+ *
+ * Description : Marks a socket for close on execute.
+ *
+ * Used so that external filters have no direct
+ * access to sockets they shouldn't care about.
+ *
+ * Not implemented for all platforms.
+ *
+ * Parameters :
+ * 1 : fd = The socket to mark
+ *
+ * Returns : void.
+ *
+ *********************************************************************/
+void mark_socket_for_close_on_execute(jb_socket fd)
+{
+#ifdef FEATURE_PTHREAD
+ int ret;
+
+ ret = fcntl(fd, F_SETFD, FD_CLOEXEC);
+
+ if (ret == -1)
+ {
+ log_error(LOG_LEVEL_ERROR,
+ "fcntl(%d, F_SETFD, FD_CLOEXEC) failed", fd);
+ }
+#else
+#warning "Sockets will be visible to external filters"
+#endif
+}
+#endif /* def FEATURE_EXTERNAL_FILTERS */
+
/*
Local Variables:
tab-width: 3