Rebuild config
[privoxy.git] / jbsockets.c
index 2e20a83..51d1271 100644 (file)
@@ -1,4 +1,4 @@
-const char jbsockets_rcs[] = "$Id: jbsockets.c,v 1.114 2012/03/09 17:56:41 fabiankeil Exp $";
+const char jbsockets_rcs[] = "$Id: jbsockets.c,v 1.125 2014/06/02 06:19:05 fabiankeil Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/jbsockets.c,v $
@@ -8,7 +8,7 @@ const char jbsockets_rcs[] = "$Id: jbsockets.c,v 1.114 2012/03/09 17:56:41 fabia
  *                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-2014 the
  *                Privoxy team. http://www.privoxy.org/
  *
  *                Based on the Internet Junkbuster originally written
@@ -83,7 +83,6 @@ const char jbsockets_rcs[] = "$Id: jbsockets.c,v 1.114 2012/03/09 17:56:41 fabia
 
 #endif
 
-#ifdef FEATURE_CONNECTION_KEEP_ALIVE
 #ifdef HAVE_POLL
 #ifdef __GLIBC__
 #include <sys/poll.h>
@@ -91,7 +90,6 @@ const char jbsockets_rcs[] = "$Id: jbsockets.c,v 1.114 2012/03/09 17:56:41 fabia
 #include <poll.h>
 #endif /* def __GLIBC__ */
 #endif /* HAVE_POLL */
-#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
 
 #include "project.h"
 
@@ -133,7 +131,7 @@ static jb_socket no_rfc2553_connect_to(const char *host, int portnum, struct cli
  *
  * Parameters  :
  *          1  :  host = hostname to connect to
- *          2  :  portnum = port to connent on (XXX: should be unsigned)
+ *          2  :  portnum = port to connect to (XXX: should be unsigned)
  *          3  :  csp = Current client state (buffers, headers, etc...)
  *
  * Returns     :  JB_INVALID_SOCKET => failure, else it is the socket
@@ -280,6 +278,21 @@ static jb_socket rfc2553_connect_to(const char *host, int portnum, struct client
          continue;
       }
 
+#ifndef _WIN32
+      if (fd >= FD_SETSIZE)
+      {
+         log_error(LOG_LEVEL_ERROR,
+            "Server socket number too high to use select(): %d >= %d",
+            fd, FD_SETSIZE);
+         close_socket(fd);
+         return JB_INVALID_SOCKET;
+      }
+#endif
+
+#ifdef FEATURE_EXTERNAL_FILTERS
+      mark_socket_for_close_on_execute(fd);
+#endif
+
 #ifdef TCP_NODELAY
       {  /* turn off TCP coalescence */
          int mi = 1;
@@ -462,6 +475,17 @@ static jb_socket no_rfc2553_connect_to(const char *host, int portnum, struct cli
       return(JB_INVALID_SOCKET);
    }
 
+#ifndef _WIN32
+   if (fd >= FD_SETSIZE)
+   {
+      log_error(LOG_LEVEL_ERROR,
+         "Server socket number too high to use select(): %d >= %d",
+         fd, FD_SETSIZE);
+      close_socket(fd);
+      return JB_INVALID_SOCKET;
+   }
+#endif
+
 #ifdef TCP_NODELAY
    {  /* turn off TCP coalescence */
       int mi = 1;
@@ -474,6 +498,9 @@ static jb_socket no_rfc2553_connect_to(const char *host, int portnum, struct cli
    {
       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__) */
 
@@ -728,13 +755,13 @@ void drain_and_close_socket(jb_socket fd)
       int bytes_drained;
 
 #ifdef HAVE_SHUTDOWN
-/* Apparently Windows has shutdown() but now SHUT_WR */
+/* Apparently Windows has shutdown() but not SHUT_WR. */
 #ifndef SHUT_WR
 #define SHUT_WR 1
 #endif
       if (0 != shutdown(fd, SHUT_WR))
       {
-         log_error(LOG_LEVEL_ERROR, "Failed to shutdown socket %d %E", fd);
+         log_error(LOG_LEVEL_CONNECT, "Failed to shutdown socket %d: %E", fd);
       }
 #endif
 #define ARBITRARY_DRAIN_LIMIT 10000
@@ -742,10 +769,19 @@ void drain_and_close_socket(jb_socket fd)
       {
          char drainage[500];
 
+         if (!data_is_available(fd, 0))
+         {
+            /*
+             * If there is no data available right now, don't try
+             * to drain the socket as read_socket() could block.
+             */
+            break;
+         }
+
          bytes_drained = read_socket(fd, drainage, sizeof(drainage));
          if (bytes_drained < 0)
          {
-            log_error(LOG_LEVEL_ERROR, "Failed to drain socket %d %E", fd);
+            log_error(LOG_LEVEL_CONNECT, "Failed to drain socket %d: %E", fd);
          }
          else if (bytes_drained > 0)
          {
@@ -879,6 +915,10 @@ int bind_port(const char *hostnam, int portnum, jb_socket *pfd)
    fd = socket(AF_INET, SOCK_STREAM, 0);
 #endif /* def HAVE_RFC2553 */
 
+#ifdef FEATURE_EXTERNAL_FILTERS
+   mark_socket_for_close_on_execute(fd);
+#endif
+
 #ifdef _WIN32
    if (fd == JB_INVALID_SOCKET)
 #else
@@ -1005,7 +1045,7 @@ void get_host_information(jb_socket afd, char **ip_address, char **port,
    struct sockaddr_in server;
    struct hostent *host = NULL;
 #endif /* HAVE_RFC2553 */
-#if defined(_WIN32) || defined(__OS2__) || defined(__APPLE_CC__) || defined(AMIGA)
+#if defined(_WIN32) || defined(__OS2__) || defined(AMIGA)
    /* according to accept_connection() this fixes a warning. */
    int s_length, s_length_provided;
 #else
@@ -1043,7 +1083,7 @@ void get_host_information(jb_socket afd, char **ip_address, char **port,
  *      configured with --disable-ipv6-support.
  *      The proper fix is to not use NI_MAXSERV in
  *      that case. It works by accident on other platforms
- *      as <netdb.h> in included unconditionally there.
+ *      as <netdb.h> is included unconditionally there.
  */
 #ifndef NI_MAXSERV
 #define NI_MAXSERV 32
@@ -1175,7 +1215,7 @@ int accept_connection(struct client_state * csp, jb_socket fds[])
    struct sockaddr_in client;
 #endif
    jb_socket afd;
-#if defined(_WIN32) || defined(__OS2__) || defined(__APPLE_CC__) || defined(AMIGA)
+#if defined(_WIN32) || defined(__OS2__) || defined(AMIGA)
    /* Wierdness - fix a warning. */
    int c_length;
 #else
@@ -1267,6 +1307,33 @@ int accept_connection(struct client_state * csp, jb_socket fds[])
    }
 #endif
 
+#ifdef SO_LINGER
+   {
+      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)))
+      {
+         log_error(LOG_LEVEL_ERROR, "Setting SO_LINGER on socket %d failed.", afd);
+      }
+   }
+#endif
+
+#ifndef _WIN32
+   if (afd >= FD_SETSIZE)
+   {
+      log_error(LOG_LEVEL_ERROR,
+         "Client socket number too high to use select(): %d >= %d",
+         afd, FD_SETSIZE);
+      close_socket(afd);
+      return 0;
+   }
+#endif
+
+#ifdef FEATURE_EXTERNAL_FILTERS
+   mark_socket_for_close_on_execute(afd);
+#endif
+
    csp->cfd = afd;
 #ifdef HAVE_RFC2553
    csp->ip_addr_str = malloc(NI_MAXHOST);
@@ -1411,7 +1478,6 @@ unsigned long resolve_hostname_to_ip(const char *host)
 }
 
 
-#ifdef FEATURE_CONNECTION_KEEP_ALIVE
 /*********************************************************************
  *
  * Function    :  socket_is_still_alive
@@ -1465,9 +1531,44 @@ int socket_is_still_alive(jb_socket sfd)
 
    return (no_data_waiting || (1 == recv(sfd, buf, 1, MSG_PEEK)));
 }
-#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
 
 
+#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