Update the forward-override{} example to be consistent with the tagging example
[privoxy.git] / jbsockets.c
index c16e75f..96f2294 100644 (file)
@@ -1,4 +1,4 @@
-const char jbsockets_rcs[] = "$Id: jbsockets.c,v 1.118 2012/10/21 12:44:58 fabiankeil Exp $";
+const char jbsockets_rcs[] = "$Id: jbsockets.c,v 1.126 2014/06/02 06:22:20 fabiankeil Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/jbsockets.c,v $
@@ -8,7 +8,7 @@ const char jbsockets_rcs[] = "$Id: jbsockets.c,v 1.118 2012/10/21 12:44:58 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
@@ -99,6 +99,7 @@ const char jbsockets_rcs[] = "$Id: jbsockets.c,v 1.118 2012/10/21 12:44:58 fabia
 #include "jbsockets.h"
 #include "filters.h"
 #include "errlog.h"
+#include "miscutil.h"
 
 /* Mac OSX doesn't define AI_NUMERICSESRV */
 #ifndef AI_NUMERICSERV
@@ -131,7 +132,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
@@ -232,14 +233,7 @@ static jb_socket rfc2553_connect_to(const char *host, int portnum, struct client
       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)
    {
@@ -278,6 +272,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;
@@ -460,6 +469,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;
@@ -472,6 +492,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__) */
 
@@ -740,6 +763,15 @@ 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)
          {
@@ -877,6 +909,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
@@ -1003,7 +1039,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
@@ -1041,27 +1077,15 @@ 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
 #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);
@@ -1087,13 +1111,7 @@ void get_host_information(jb_socket afd, char **ip_address, char **port,
       }
 
 #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)
@@ -1173,7 +1191,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
@@ -1277,15 +1295,24 @@ int accept_connection(struct client_state * csp, jb_socket fds[])
    }
 #endif
 
-   csp->cfd = afd;
-#ifdef HAVE_RFC2553
-   csp->ip_addr_str = malloc(NI_MAXHOST);
-   if (NULL == csp->ip_addr_str)
+#ifndef _WIN32
+   if (afd >= FD_SETSIZE)
    {
       log_error(LOG_LEVEL_ERROR,
-         "Out of memory while getting the client's IP address.");
+         "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_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)
@@ -1476,6 +1503,42 @@ int socket_is_still_alive(jb_socket sfd)
 }
 
 
+#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