Keep a thread around to timeout alive connections
[privoxy.git] / gateway.c
index 56b15fb..73c8a3a 100644 (file)
--- a/gateway.c
+++ b/gateway.c
@@ -1,4 +1,4 @@
-const char gateway_rcs[] = "$Id: gateway.c,v 1.38 2008/10/24 17:33:00 fabiankeil Exp $";
+const char gateway_rcs[] = "$Id: gateway.c,v 1.46 2008/12/13 11:07:23 fabiankeil Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/gateway.c,v $
@@ -34,6 +34,31 @@ const char gateway_rcs[] = "$Id: gateway.c,v 1.38 2008/10/24 17:33:00 fabiankeil
  *
  * Revisions   :
  *    $Log: gateway.c,v $
+ *    Revision 1.46  2008/12/13 11:07:23  fabiankeil
+ *    Remove duplicated debugging checks
+ *    in connection_destination_matches().
+ *
+ *    Revision 1.45  2008/12/04 18:17:07  fabiankeil
+ *    Fix some cparser warnings.
+ *
+ *    Revision 1.44  2008/11/22 11:54:04  fabiankeil
+ *    Move log message around to include the socket number.
+ *
+ *    Revision 1.43  2008/11/13 09:15:51  fabiankeil
+ *    Make keep_alive_timeout static.
+ *
+ *    Revision 1.42  2008/11/13 09:08:42  fabiankeil
+ *    Add new config option: keep-alive-timeout.
+ *
+ *    Revision 1.41  2008/11/08 15:29:58  fabiankeil
+ *    Unify two debug messages.
+ *
+ *    Revision 1.40  2008/11/08 15:14:05  fabiankeil
+ *    Fix duplicated debugging check.
+ *
+ *    Revision 1.39  2008/10/25 11:33:01  fabiankeil
+ *    Remove already out-commented line left over from debugging.
+ *
  *    Revision 1.38  2008/10/24 17:33:00  fabiankeil
  *    - Tone the "keep-alive support is experimental" warning
  *      down a bit as hackish 0-chunk detection has been
@@ -304,8 +329,7 @@ static const char socks_userid[] = "anonymous";
 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
 
 #define MAX_REUSABLE_CONNECTIONS 100
-/* XXX: should be a config option. */
-#define CONNECTION_KEEP_ALIVE_TIMEOUT 3 * 60
+static int keep_alive_timeout = DEFAULT_KEEP_ALIVE_TIMEOUT;
 
 struct reusable_connection
 {
@@ -544,7 +568,7 @@ void forget_connection(jb_socket sfd)
  * Function    :  connection_destination_matches
  *
  * Description :  Determines whether a remembered connection can
- *                be reused. That is whether the destination and
+ *                be reused. That is, whether the destination and
  *                the forwarding settings match.
  *
  * Parameters  :
@@ -559,39 +583,6 @@ static int connection_destination_matches(const struct reusable_connection *conn
                                           const struct http_request *http,
                                           const struct forward_spec *fwd)
 {
-   /* XXX: Start of duplicated checks for debugging purposes. */
-   if (strcmpic(connection->host, http->host))
-   {
-      return FALSE;
-   }
-
-   if (connection->forwarder_type != fwd->type)
-   {
-      log_error(LOG_LEVEL_CONNECT, "Type mismatch: %d %d (%s)",
-         connection->forwarder_type, fwd->type, http->host);
-      return FALSE;
-   }
-   if (connection->gateway_port   != fwd->gateway_port)
-   {
-      log_error(LOG_LEVEL_CONNECT, "Gateway port mismatch: %d %d (%s)",
-         connection->gateway_port, fwd->gateway_port, http->host);
-      return FALSE;
-   }
-   if (connection->forward_port   != fwd->forward_port)
-   {
-      log_error(LOG_LEVEL_CONNECT, "Forward port mismatch: %d %d (%s)",
-         connection->forward_port, fwd->forward_port, http->host);
-      return FALSE;
-   }
-   if (connection->forward_port   != fwd->forward_port)
-   {
-      log_error(LOG_LEVEL_CONNECT, "Server port mismatch: %d %d (%s)",
-         connection->forward_port, fwd->forward_port, http->host);
-      return FALSE;
-   }
-
-   /* XXX: End of duplicated checks for debugging purposes. */
-
    if ((connection->forwarder_type != fwd->type)
     || (connection->gateway_port   != fwd->gateway_port)
     || (connection->forward_port   != fwd->forward_port)
@@ -632,12 +623,15 @@ static int connection_destination_matches(const struct reusable_connection *conn
  *
  * Parameters  :  none
  *
- * Returns     :  void
+ * Returns     :  Number of connections that are still alive.
  *
  *********************************************************************/
-static void close_unusable_connections(void)
+int close_unusable_connections(void)
 {
    unsigned int slot = 0;
+   int connections_alive = 0;
+
+   privoxy_mutex_lock(&connection_reuse_mutex);
 
    for (slot = 0; slot < SZ(reusable_connection); slot++)
    {
@@ -646,29 +640,38 @@ static void close_unusable_connections(void)
       {
          time_t time_open = time(NULL) - reusable_connection[slot].timestamp;
 
-         if (CONNECTION_KEEP_ALIVE_TIMEOUT < time_open)
+         if (keep_alive_timeout < time_open)
          {
             log_error(LOG_LEVEL_CONNECT,
-               "The connection to %s:%d in slot %d timed out. Closing.",
-               reusable_connection[slot].host, reusable_connection[slot].port,
-               slot);
+               "The connection to %s:%d in slot %d timed out. "
+               "Closing socket %d. Timeout is: %d.",
+               reusable_connection[slot].host,
+               reusable_connection[slot].port, slot,
+               reusable_connection[slot].sfd, keep_alive_timeout);
             close_socket(reusable_connection[slot].sfd);
             mark_connection_closed(&reusable_connection[slot]);
-            continue;
          }
-
-         if (!socket_is_still_usable(reusable_connection[slot].sfd))
+         else if (!socket_is_still_usable(reusable_connection[slot].sfd))
          {
             log_error(LOG_LEVEL_CONNECT,
-               "Socket %d for %s:%d in slot %d is no longer usable. Closing.",
-               reusable_connection[slot].sfd, reusable_connection[slot].host,
-               reusable_connection[slot].port, slot);
+               "The connection to %s:%d in slot %d is no longer usable. "
+               "Closing socket %d.", reusable_connection[slot].host,
+               reusable_connection[slot].port, slot,
+               reusable_connection[slot].sfd);
             close_socket(reusable_connection[slot].sfd);
             mark_connection_closed(&reusable_connection[slot]);
-            continue;
+         }
+         else
+         {
+            connections_alive++;
          }
       }
    }
+
+   privoxy_mutex_unlock(&connection_reuse_mutex);
+
+   return connections_alive;
+
 }
 
 
@@ -753,10 +756,10 @@ static jb_socket get_reusable_connection(const struct http_request *http,
    jb_socket sfd = JB_INVALID_SOCKET;
    unsigned int slot = 0;
 
-   privoxy_mutex_lock(&connection_reuse_mutex);
-
    close_unusable_connections();
 
+   privoxy_mutex_lock(&connection_reuse_mutex);
+
    for (slot = 0; slot < SZ(reusable_connection); slot++)
    {
       if (!reusable_connection[slot].in_use
@@ -824,6 +827,25 @@ static int mark_connection_unused(jb_socket sfd)
    return socket_found;
 
 }
+
+
+/*********************************************************************
+ *
+ * Function    :  set_keep_alive_timeout
+ *
+ * Description :  Sets the timeout after which open
+ *                connections will no longer be reused.
+ *
+ * Parameters  :
+ *          1  :  timeout = The timeout in seconds.
+ *
+ * Returns     :  void
+ *
+ *********************************************************************/
+void set_keep_alive_timeout(int timeout)
+{
+   keep_alive_timeout = timeout;
+}
 #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
 
 
@@ -852,13 +874,7 @@ jb_socket forwarded_connect(const struct forward_spec * fwd,
 
 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
    sfd = get_reusable_connection(http, fwd);
-   if (JB_INVALID_SOCKET == sfd)
-   {
-      log_error(LOG_LEVEL_CONNECT,
-         "No reusable socket for %s:%d found. Opening a new one.",
-         http->host, http->port);
-   }
-   else
+   if (JB_INVALID_SOCKET != sfd)
    {
       return sfd;
    }
@@ -897,6 +913,13 @@ jb_socket forwarded_connect(const struct forward_spec * fwd,
             "SOCKS4 impossible internal error - bad SOCKS type.");
    }
 
+   if (JB_INVALID_SOCKET != sfd)
+   {
+      log_error(LOG_LEVEL_CONNECT,
+         "Created new connection to %s:%d on socket %d.",
+         http->host, http->port, sfd);
+   }
+
    return sfd;
 
 }
@@ -1069,7 +1092,6 @@ static jb_socket socks4_connect(const struct forward_spec * fwd,
    {
       case SOCKS_REQUEST_GRANTED:
          return(sfd);
-         break;
       case SOCKS_REQUEST_REJECT:
          errstr = "SOCKS request rejected or failed.";
          errno = EINVAL;
@@ -1192,7 +1214,7 @@ static jb_socket socks5_connect(const struct forward_spec *fwd,
    }
 
    hostlen = strlen(target_host);
-   if (hostlen > 255)
+   if (hostlen > (size_t)255)
    {
       errstr = "target host name is longer than 255 characters";
       err = 1;
@@ -1280,7 +1302,7 @@ static jb_socket socks5_connect(const struct forward_spec *fwd,
    cbuf[client_pos++] = '\x00'; /* Reserved, must be 0x00 */
    cbuf[client_pos++] = '\x03'; /* Address is domain name */
    cbuf[client_pos++] = (char)(hostlen & 0xffu);
-   assert(sizeof(cbuf) - client_pos > 255);
+   assert(sizeof(cbuf) - client_pos > (size_t)255);
    /* Using strncpy because we really want the nul byte padding. */
    strncpy(cbuf + client_pos, target_host, sizeof(cbuf) - client_pos);
    client_pos += (hostlen & 0xffu);