Remove a double space in an error message
[privoxy.git] / gateway.c
index 855ebf2..a8da953 100644 (file)
--- a/gateway.c
+++ b/gateway.c
@@ -1,4 +1,4 @@
-const char gateway_rcs[] = "$Id: gateway.c,v 1.55 2009/07/05 12:01:45 fabiankeil Exp $";
+const char gateway_rcs[] = "$Id: gateway.c,v 1.72 2011/03/27 14:00:36 fabiankeil Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/gateway.c,v $
@@ -7,7 +7,7 @@ const char gateway_rcs[] = "$Id: gateway.c,v 1.55 2009/07/05 12:01:45 fabiankeil
  *                using a "forwarder" (i.e. HTTP proxy and/or a SOCKS4
  *                or SOCKS5 proxy).
  *
- * Copyright   :  Written by and Copyright (C) 2001-2009 the SourceForge
+ * Copyright   :  Written by and Copyright (C) 2001-2009 the
  *                Privoxy team. http://www.privoxy.org/
  *
  *                Based on the Internet Junkbuster originally written
@@ -88,21 +88,24 @@ static jb_socket socks5_connect(const struct forward_spec *fwd,
                                 int target_port,
                                 struct client_state *csp);
 
+enum {
+   SOCKS4_REQUEST_GRANTED        =  90,
+   SOCKS4_REQUEST_REJECT         =  91,
+   SOCKS4_REQUEST_IDENT_FAILED   =  92,
+   SOCKS4_REQUEST_IDENT_CONFLICT =  93
+};
 
-#define SOCKS_REQUEST_GRANTED          90
-#define SOCKS_REQUEST_REJECT           91
-#define SOCKS_REQUEST_IDENT_FAILED     92
-#define SOCKS_REQUEST_IDENT_CONFLICT   93
-
-#define SOCKS5_REQUEST_GRANTED             0
-#define SOCKS5_REQUEST_FAILED              1
-#define SOCKS5_REQUEST_DENIED              2
-#define SOCKS5_REQUEST_NETWORK_UNREACHABLE 3
-#define SOCKS5_REQUEST_HOST_UNREACHABLE    4
-#define SOCKS5_REQUEST_CONNECTION_REFUSED  5
-#define SOCKS5_REQUEST_TTL_EXPIRED         6
-#define SOCKS5_REQUEST_PROTOCOL_ERROR      7
-#define SOCKS5_REQUEST_BAD_ADDRESS_TYPE    8
+enum {
+   SOCKS5_REQUEST_GRANTED             = 0,
+   SOCKS5_REQUEST_FAILED              = 1,
+   SOCKS5_REQUEST_DENIED              = 2,
+   SOCKS5_REQUEST_NETWORK_UNREACHABLE = 3,
+   SOCKS5_REQUEST_HOST_UNREACHABLE    = 4,
+   SOCKS5_REQUEST_CONNECTION_REFUSED  = 5,
+   SOCKS5_REQUEST_TTL_EXPIRED         = 6,
+   SOCKS5_REQUEST_PROTOCOL_ERROR      = 7,
+   SOCKS5_REQUEST_BAD_ADDRESS_TYPE    = 8
+};
 
 /* structure of a socks client operation */
 struct socks_op {
@@ -125,7 +128,7 @@ struct socks_reply {
 
 static const char socks_userid[] = "anonymous";
 
-#ifdef FEATURE_CONNECTION_KEEP_ALIVE
+#ifdef FEATURE_CONNECTION_SHARING
 
 #define MAX_REUSABLE_CONNECTIONS 100
 static unsigned int keep_alive_timeout = DEFAULT_KEEP_ALIVE_TIMEOUT;
@@ -169,22 +172,20 @@ extern void initialize_reusable_connections(void)
  *
  * Function    :  remember_connection
  *
- * Description :  Remembers a connection for reuse later on.
+ * Description :  Remembers a server connection for reuse later on.
  *
  * Parameters  :
- *          1  :  csp = Current client state (buffers, headers, etc...)
- *          2  :  fwd = The forwarder settings used.
+ *          1  :  connection = The server connection to remember.
  *
  * Returns     : void
  *
  *********************************************************************/
-void remember_connection(const struct client_state *csp, const struct forward_spec *fwd)
+void remember_connection(const struct reusable_connection *connection)
 {
    unsigned int slot = 0;
    int free_slot_found = FALSE;
-   const struct reusable_connection *connection = &csp->server_connection;
-   const struct http_request *http = csp->http;
 
+   assert(NULL != connection);
    assert(connection->sfd != JB_INVALID_SOCKET);
 
    if (mark_connection_unused(connection))
@@ -202,7 +203,7 @@ void remember_connection(const struct client_state *csp, const struct forward_sp
          assert(reusable_connection[slot].in_use == 0);
          log_error(LOG_LEVEL_CONNECT,
             "Remembering socket %d for %s:%d in slot %d.",
-            connection->sfd, http->host, http->port, slot);
+            connection->sfd, connection->host, connection->port, slot);
          free_slot_found = TRUE;
          break;
       }
@@ -212,35 +213,36 @@ void remember_connection(const struct client_state *csp, const struct forward_sp
    {
       log_error(LOG_LEVEL_CONNECT,
         "No free slots found to remembering socket for %s:%d. Last slot %d.",
-        http->host, http->port, slot);
+        connection->host, connection->port, slot);
       privoxy_mutex_unlock(&connection_reuse_mutex);
       close_socket(connection->sfd);
       return;
    }
 
-   assert(NULL != http->host);
-   reusable_connection[slot].host = strdup(http->host);
+   assert(NULL != connection->host);
+   reusable_connection[slot].host = strdup(connection->host);
    if (NULL == reusable_connection[slot].host)
    {
       log_error(LOG_LEVEL_FATAL, "Out of memory saving socket.");
    }
    reusable_connection[slot].sfd = connection->sfd;
-   reusable_connection[slot].port = http->port;
+   reusable_connection[slot].port = connection->port;
    reusable_connection[slot].in_use = 0;
    reusable_connection[slot].timestamp = connection->timestamp;
+   reusable_connection->request_sent = connection->request_sent;
+   reusable_connection->response_received = connection->response_received;
    reusable_connection[slot].keep_alive_timeout = connection->keep_alive_timeout;
 
-   assert(NULL != fwd);
    assert(reusable_connection[slot].gateway_host == NULL);
    assert(reusable_connection[slot].gateway_port == 0);
    assert(reusable_connection[slot].forwarder_type == SOCKS_NONE);
    assert(reusable_connection[slot].forward_host == NULL);
    assert(reusable_connection[slot].forward_port == 0);
 
-   reusable_connection[slot].forwarder_type = fwd->type;
-   if (NULL != fwd->gateway_host)
+   reusable_connection[slot].forwarder_type = connection->forwarder_type;
+   if (NULL != connection->gateway_host)
    {
-      reusable_connection[slot].gateway_host = strdup(fwd->gateway_host);
+      reusable_connection[slot].gateway_host = strdup(connection->gateway_host);
       if (NULL == reusable_connection[slot].gateway_host)
       {
          log_error(LOG_LEVEL_FATAL, "Out of memory saving gateway_host.");
@@ -250,11 +252,11 @@ void remember_connection(const struct client_state *csp, const struct forward_sp
    {
       reusable_connection[slot].gateway_host = NULL;
    }
-   reusable_connection[slot].gateway_port = fwd->gateway_port;
+   reusable_connection[slot].gateway_port = connection->gateway_port;
 
-   if (NULL != fwd->forward_host)
+   if (NULL != connection->forward_host)
    {
-      reusable_connection[slot].forward_host = strdup(fwd->forward_host);
+      reusable_connection[slot].forward_host = strdup(connection->forward_host);
       if (NULL == reusable_connection[slot].forward_host)
       {
          log_error(LOG_LEVEL_FATAL, "Out of memory saving forward_host.");
@@ -264,12 +266,14 @@ void remember_connection(const struct client_state *csp, const struct forward_sp
    {
       reusable_connection[slot].forward_host = NULL;
    }
-   reusable_connection[slot].forward_port = fwd->forward_port;
+   reusable_connection[slot].forward_port = connection->forward_port;
 
    privoxy_mutex_unlock(&connection_reuse_mutex);
 }
+#endif /* def FEATURE_CONNECTION_SHARING */
 
 
+#ifdef FEATURE_CONNECTION_KEEP_ALIVE
 /*********************************************************************
  *
  * Function    :  mark_connection_closed
@@ -289,6 +293,8 @@ void mark_connection_closed(struct reusable_connection *closed_connection)
    freez(closed_connection->host);
    closed_connection->port = 0;
    closed_connection->timestamp = 0;
+   closed_connection->request_sent = 0;
+   closed_connection->response_received = 0;
    closed_connection->keep_alive_timeout = 0;
    closed_connection->forwarder_type = SOCKS_NONE;
    freez(closed_connection->gateway_host);
@@ -296,8 +302,10 @@ void mark_connection_closed(struct reusable_connection *closed_connection)
    freez(closed_connection->forward_host);
    closed_connection->forward_port = 0;
 }
+#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
 
 
+#ifdef FEATURE_CONNECTION_SHARING
 /*********************************************************************
  *
  * Function    :  forget_connection
@@ -341,8 +349,10 @@ void forget_connection(jb_socket sfd)
 
    privoxy_mutex_unlock(&connection_reuse_mutex);
 }
+#endif /* def FEATURE_CONNECTION_SHARING */
 
 
+#ifdef FEATURE_CONNECTION_KEEP_ALIVE
 /*********************************************************************
  *
  * Function    :  connection_destination_matches
@@ -376,7 +386,9 @@ int connection_destination_matches(const struct reusable_connection *connection,
          && strcmpic(connection->gateway_host, fwd->gateway_host))
        && (connection->gateway_host != fwd->gateway_host))
    {
-      log_error(LOG_LEVEL_CONNECT, "Gateway mismatch.");
+      log_error(LOG_LEVEL_CONNECT,
+         "Gateway mismatch. Previous gateway: %s. Current gateway: %s",
+         connection->gateway_host, fwd->gateway_host);
       return FALSE;
    }
 
@@ -385,15 +397,19 @@ int connection_destination_matches(const struct reusable_connection *connection,
          && strcmpic(connection->forward_host, fwd->forward_host))
       && (connection->forward_host != fwd->forward_host))
    {
-      log_error(LOG_LEVEL_CONNECT, "Forwarding proxy mismatch.");
+      log_error(LOG_LEVEL_CONNECT,
+         "Forwarding proxy mismatch. Previous proxy: %s. Current proxy: %s",
+         connection->forward_host, fwd->forward_host);
       return FALSE;
    }
 
    return (!strcmpic(connection->host, http->host));
 
 }
+#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
 
 
+#ifdef FEATURE_CONNECTION_SHARING
 /*********************************************************************
  *
  * Function    :  close_unusable_connections
@@ -419,20 +435,23 @@ int close_unusable_connections(void)
          && (JB_INVALID_SOCKET != reusable_connection[slot].sfd))
       {
          time_t time_open = time(NULL) - reusable_connection[slot].timestamp;
+         time_t latency = (reusable_connection[slot].response_received -
+            reusable_connection[slot].request_sent) / 2;
 
-         if (reusable_connection[slot].keep_alive_timeout < time_open)
+         if (reusable_connection[slot].keep_alive_timeout < time_open + latency)
          {
             log_error(LOG_LEVEL_CONNECT,
                "The connection to %s:%d in slot %d timed out. "
-               "Closing socket %d. Timeout is: %d.",
+               "Closing socket %d. Timeout is: %d. Assumed latency: %d.",
                reusable_connection[slot].host,
                reusable_connection[slot].port, slot,
                reusable_connection[slot].sfd,
-               reusable_connection[slot].keep_alive_timeout);
+               reusable_connection[slot].keep_alive_timeout,
+               latency);
             close_socket(reusable_connection[slot].sfd);
             mark_connection_closed(&reusable_connection[slot]);
          }
-         else if (!socket_is_still_usable(reusable_connection[slot].sfd))
+         else if (!socket_is_still_alive(reusable_connection[slot].sfd))
          {
             log_error(LOG_LEVEL_CONNECT,
                "The connection to %s:%d in slot %d is no longer usable. "
@@ -491,8 +510,13 @@ static jb_socket get_reusable_connection(const struct http_request *http,
             reusable_connection[slot].in_use = TRUE;
             sfd = reusable_connection[slot].sfd;
             log_error(LOG_LEVEL_CONNECT,
-               "Found reusable socket %d for %s:%d in slot %d.",
-               sfd, reusable_connection[slot].host, reusable_connection[slot].port, slot);
+               "Found reusable socket %d for %s:%d in slot %d. "
+               "Timestamp made %d seconds ago. Timeout: %d. Latency: %d.",
+               sfd, reusable_connection[slot].host, reusable_connection[slot].port,
+               slot, time(NULL) - reusable_connection[slot].timestamp,
+               reusable_connection[slot].keep_alive_timeout,
+               (int)(reusable_connection[slot].response_received -
+               reusable_connection[slot].request_sent));
             break;
          }
       }
@@ -567,7 +591,7 @@ void set_keep_alive_timeout(unsigned int timeout)
 {
    keep_alive_timeout = timeout;
 }
-#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
+#endif /* def FEATURE_CONNECTION_SHARING */
 
 
 /*********************************************************************
@@ -593,7 +617,7 @@ jb_socket forwarded_connect(const struct forward_spec * fwd,
    int dest_port;
    jb_socket sfd = JB_INVALID_SOCKET;
 
-#ifdef FEATURE_CONNECTION_KEEP_ALIVE
+#ifdef FEATURE_CONNECTION_SHARING
    if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_SHARING)
       && !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED))
    {
@@ -603,7 +627,7 @@ jb_socket forwarded_connect(const struct forward_spec * fwd,
          return sfd;
       }
    }
-#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
+#endif /* def FEATURE_CONNECTION_SHARING */
 
    /* Figure out if we need to connect to the web server or a HTTP proxy. */
    if (fwd->forward_host)
@@ -678,7 +702,7 @@ static jb_socket socks4_connect(const struct forward_spec * fwd,
                                 int target_port,
                                 struct client_state *csp)
 {
-   unsigned int web_server_addr;
+   unsigned long web_server_addr;
    char buf[BUFFER_SIZE];
    struct socks_op    *c = (struct socks_op    *)buf;
    struct socks_reply *s = (struct socks_reply *)buf;
@@ -785,12 +809,22 @@ static jb_socket socks4_connect(const struct forward_spec * fwd,
 
    if (sfd == JB_INVALID_SOCKET)
    {
-      /*
-       * XXX: connect_to should fill in the exact reason.
-       * Most likely resolving the IP of the forwarder failed.
-       */
-      errstr = "connect_to failed: see logfile for details";
+      /* The error an its reason have already been logged by connect_to()  */
+      return(JB_INVALID_SOCKET);
+   }
+   else if (!data_is_available(sfd, csp->config->socket_timeout))
+   {
+      if (socket_is_still_alive(sfd))
+      {
+         errstr = "SOCKS4 negotiation timed out";
+      }
+      else
+      {
+         errstr = "SOCKS4 negotiation got aborted by the server";
+      }
+      log_error(LOG_LEVEL_CONNECT, "socks4_connect: %s", errstr);
       err = 1;
+      close_socket(sfd);
    }
    else if (write_socket(sfd, (char *)c, csiz))
    {
@@ -815,18 +849,18 @@ static jb_socket socks4_connect(const struct forward_spec * fwd,
 
    switch (s->cd)
    {
-      case SOCKS_REQUEST_GRANTED:
+      case SOCKS4_REQUEST_GRANTED:
          return(sfd);
-      case SOCKS_REQUEST_REJECT:
+      case SOCKS4_REQUEST_REJECT:
          errstr = "SOCKS request rejected or failed.";
          errno = EINVAL;
          break;
-      case SOCKS_REQUEST_IDENT_FAILED:
+      case SOCKS4_REQUEST_IDENT_FAILED:
          errstr = "SOCKS request rejected because "
             "SOCKS server cannot connect to identd on the client.";
          errno = EACCES;
          break;
-      case SOCKS_REQUEST_IDENT_CONFLICT:
+      case SOCKS4_REQUEST_IDENT_CONFLICT:
          errstr = "SOCKS request rejected because "
             "the client program and identd report "
             "different user-ids.";
@@ -987,7 +1021,20 @@ static jb_socket socks5_connect(const struct forward_spec *fwd,
       return(JB_INVALID_SOCKET);
    }
 
-   if (read_socket(sfd, sbuf, sizeof(sbuf)) != 2)
+   if (!data_is_available(sfd, csp->config->socket_timeout))
+   {
+      if (socket_is_still_alive(sfd))
+      {
+         errstr = "SOCKS5 negotiation timed out";
+      }
+      else
+      {
+         errstr = "SOCKS5 negotiation got aborted by the server";
+      }
+      err = 1;
+   }
+
+   if (!err && read_socket(sfd, sbuf, sizeof(sbuf)) != 2)
    {
       errstr = "SOCKS5 negotiation read failed";
       err = 1;
@@ -1052,7 +1099,7 @@ static jb_socket socks5_connect(const struct forward_spec *fwd,
    }
    else if (server_size > 20)
    {
-      /* This is somewhat unexpected but doesn't realy matter. */
+      /* This is somewhat unexpected but doesn't really matter. */
       log_error(LOG_LEVEL_CONNECT, "socks5_connect: read %d bytes "
          "from socks server. Would have accepted up to %d.",
          server_size, sizeof(sbuf));