Make poll() non-optional and remove select()-based fallback code
[privoxy.git] / jcc.c
diff --git a/jcc.c b/jcc.c
index e872a39..875c8a7 100644 (file)
--- a/jcc.c
+++ b/jcc.c
 #else
 #include <poll.h>
 #endif /* def __GLIBC__ */
-#else
-# ifndef FD_ZERO
-#  include <select.h>
-# endif
-#warning poll() appears to be unavailable. Your platform will become unsupported in the future.
 #endif /* HAVE_POLL */
 
 #endif
@@ -559,8 +554,6 @@ static int client_has_unsupported_expectations(const struct client_state *csp)
  *********************************************************************/
 static jb_err get_request_destination_elsewhere(struct client_state *csp, struct list *headers)
 {
-   char *req;
-
    if (!(csp->config->feature_flags & RUNTIME_FEATURE_ACCEPT_INTERCEPTED_REQUESTS))
    {
       log_error(LOG_LEVEL_ERROR, "%s's request: \'%s\' is invalid."
@@ -587,15 +580,12 @@ static jb_err get_request_destination_elsewhere(struct client_state *csp, struct
    {
       /* We can't work without destination. Go spread the news.*/
 
-      req = list_to_text(headers);
-      chomp(req);
       /* XXX: Use correct size */
       log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 400 0",
          csp->ip_addr_str, csp->http->cmd);
       log_error(LOG_LEVEL_ERROR,
-         "Privoxy was unable to get the destination for %s's request:\n%s\n%s",
-         csp->ip_addr_str, csp->http->cmd, req);
-      freez(req);
+         "Privoxy was unable to get the destination for %s's request: %s",
+         csp->ip_addr_str, csp->http->cmd);
 
       write_socket_delayed(csp->cfd, MISSING_DESTINATION_RESPONSE,
          strlen(MISSING_DESTINATION_RESPONSE), get_write_delay(csp));
@@ -843,7 +833,7 @@ static void send_crunch_response(struct client_state *csp, struct http_response
       {
          log_error(LOG_LEVEL_CRUNCH, "%s: https://%s%s", crunch_reason(rsp),
             http->hostport, http->path);
-         log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s https://%s%s %s\" %s %llu",
+         log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s https://%s%s %s\" %s %lu",
             csp->ip_addr_str, http->gpc, http->hostport, http->path,
             http->version, status_code, rsp->content_length);
       }
@@ -851,7 +841,7 @@ static void send_crunch_response(struct client_state *csp, struct http_response
 #endif
       {
          log_error(LOG_LEVEL_CRUNCH, "%s: %s", crunch_reason(rsp), http->url);
-         log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" %s %u",
+         log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" %s %lu",
             csp->ip_addr_str, http->ocmd, status_code, rsp->content_length);
       }
       /* Write the answer to the client */
@@ -1176,6 +1166,22 @@ void save_connection_destination(jb_socket sfd,
       server_connection->gateway_host = NULL;
    }
    server_connection->gateway_port = fwd->gateway_port;
+   if (NULL != fwd->auth_username)
+   {
+      server_connection->auth_username = strdup_or_die(fwd->auth_username);
+   }
+   else
+   {
+      server_connection->auth_username = NULL;
+   }
+   if (NULL != fwd->auth_password)
+   {
+      server_connection->auth_password = strdup_or_die(fwd->auth_password);
+   }
+   else
+   {
+      server_connection->auth_password = NULL;
+   }
 
    if (NULL != fwd->forward_host)
    {
@@ -1548,7 +1554,7 @@ static jb_err receive_chunked_client_request_body(struct client_state *csp)
       return JB_ERR_PARSE;
    }
    log_error(LOG_LEVEL_CONNECT,
-      "Chunked client body completely read. Length: %d", body_length);
+      "Chunked client body completely read. Length: %lu", body_length);
    csp->expected_client_content_length = body_length;
 
    return JB_ERR_OK;
@@ -2152,21 +2158,21 @@ static int send_https_request(struct client_state *csp)
          csp->http->hostport);
       return 1;
    }
-   if (flushed != 0)
+   if (flushed != 0 || csp->expected_client_content_length != 0)
    {
       if (csp->expected_client_content_length != 0)
       {
          if (csp->expected_client_content_length < flushed)
          {
             log_error(LOG_LEVEL_ERROR,
-               "Flushed %d bytes of request body while only expecting %llu",
+               "Flushed %ld bytes of request body while only expecting %llu",
                flushed, csp->expected_client_content_length);
             csp->expected_client_content_length = 0;
          }
          else
          {
             log_error(LOG_LEVEL_CONNECT,
-               "Flushed %d bytes of request body while expecting %llu",
+               "Flushed %ld bytes of request body while expecting %llu",
                flushed, csp->expected_client_content_length);
             csp->expected_client_content_length -= (unsigned)flushed;
             if (receive_and_send_encrypted_post_data(csp))
@@ -2178,7 +2184,7 @@ static int send_https_request(struct client_state *csp)
       else
       {
          log_error(LOG_LEVEL_CONNECT,
-            "Flushed %d bytes of request body", flushed);
+            "Flushed %ld bytes of request body", flushed);
       }
    }
 
@@ -2276,7 +2282,8 @@ static jb_err process_encrypted_request(struct client_state *csp)
    err = receive_encrypted_request(csp);
    if (err != JB_ERR_OK)
    {
-      if (csp->client_iob->cur == NULL)
+      if (csp->client_iob->cur == NULL ||
+          csp->client_iob->cur == csp->client_iob->eod)
       {
          /*
           * We did not receive any data, most likely because the
@@ -2573,13 +2580,7 @@ static void handle_established_connection(struct client_state *csp)
    char *hdr;
    char *p;
    int n;
-#ifdef HAVE_POLL
    struct pollfd poll_fds[2];
-#else
-   fd_set rfds;
-   jb_socket maxfd;
-   struct timeval timeout;
-#endif
    int server_body;
    int ms_iis5_hack = 0;
    unsigned long long byte_count = 0;
@@ -2618,11 +2619,6 @@ static void handle_established_connection(struct client_state *csp)
 
    http = csp->http;
 
-#ifndef HAVE_POLL
-   maxfd = (csp->cfd > csp->server_connection.sfd) ?
-      csp->cfd : csp->server_connection.sfd;
-#endif
-
    /* pass data between the client and server
     * until one or the other shuts down the connection.
     */
@@ -2636,22 +2632,6 @@ static void handle_established_connection(struct client_state *csp)
 
    for (;;)
    {
-#ifndef HAVE_POLL
-      FD_ZERO(&rfds);
-#ifdef FEATURE_CONNECTION_KEEP_ALIVE
-      if (!watch_client_socket)
-      {
-         maxfd = csp->server_connection.sfd;
-      }
-      else
-#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
-      {
-         FD_SET(csp->cfd, &rfds);
-      }
-
-      FD_SET(csp->server_connection.sfd, &rfds);
-#endif /* ndef HAVE_POLL */
-
 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
       if ((csp->flags & CSP_FLAG_CHUNKED)
          && !(csp->flags & CSP_FLAG_CONTENT_LENGTH_SET)
@@ -2676,14 +2656,14 @@ static void handle_established_connection(struct client_state *csp)
          {
             log_error(LOG_LEVEL_CONNECT,
                "Done reading from server. Content length: %llu as expected. "
-               "Bytes most recently read: %d.",
+               "Bytes most recently read: %ld.",
                byte_count, len);
          }
          else
          {
             log_error(LOG_LEVEL_CONNECT,
                "Done reading from server. Expected content length: %llu. "
-               "Actual content length: %llu. Bytes most recently read: %d.",
+               "Actual content length: %llu. Bytes most recently read: %ld.",
                csp->expected_content_length, byte_count, len);
          }
          len = 0;
@@ -2695,7 +2675,6 @@ static void handle_established_connection(struct client_state *csp)
       }
 #endif  /* FEATURE_CONNECTION_KEEP_ALIVE */
 
-#ifdef HAVE_POLL
       poll_fds[0].fd = csp->cfd;
 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
       if (!watch_client_socket)
@@ -2716,11 +2695,6 @@ static void handle_established_connection(struct client_state *csp)
       poll_fds[1].fd = csp->server_connection.sfd;
       poll_fds[1].events = POLLIN;
       n = poll(poll_fds, 2, csp->config->socket_timeout * 1000);
-#else
-      timeout.tv_sec = csp->config->socket_timeout;
-      timeout.tv_usec = 0;
-      n = select((int)maxfd + 1, &rfds, NULL, NULL, &timeout);
-#endif /* def HAVE_POLL */
 
       /*server or client not responding in timeout */
       if (n == 0)
@@ -2739,11 +2713,7 @@ static void handle_established_connection(struct client_state *csp)
       }
       else if (n < 0)
       {
-#ifdef HAVE_POLL
          log_error(LOG_LEVEL_ERROR, "poll() failed!: %E");
-#else
-         log_error(LOG_LEVEL_ERROR, "select() failed!: %E");
-#endif
          mark_server_socket_tainted(csp);
 #ifdef FEATURE_HTTPS_INSPECTION
          close_client_and_server_ssl_connections(csp);
@@ -2760,7 +2730,6 @@ static void handle_established_connection(struct client_state *csp)
        * XXX: Make sure the client doesn't use pipelining
        * behind Privoxy's back.
        */
-#ifdef HAVE_POLL
       if ((poll_fds[0].revents & (POLLERR|POLLHUP|POLLNVAL)) != 0)
       {
          log_error(LOG_LEVEL_CONNECT,
@@ -2772,9 +2741,6 @@ static void handle_established_connection(struct client_state *csp)
       }
 
       if (poll_fds[0].revents != 0)
-#else
-      if (FD_ISSET(csp->cfd, &rfds))
-#endif /* def HAVE_POLL*/
       {
          int max_bytes_to_read = (int)csp->receive_buffer_size;
 
@@ -2785,7 +2751,7 @@ static void handle_established_connection(struct client_state *csp)
             {
                /*
                 * If the next request is already waiting, we have
-                * to stop select()ing the client socket. Otherwise
+                * to stop poll()ing the client socket. Otherwise
                 * we would always return right away and get nothing
                 * else done.
                 */
@@ -2824,6 +2790,37 @@ static void handle_established_connection(struct client_state *csp)
 #ifdef FEATURE_HTTPS_INSPECTION
          if (client_use_ssl(csp))
          {
+            if (csp->http->status == 101)
+            {
+               len = ssl_recv_data(&(csp->ssl_client_attr),
+                  (unsigned char *)csp->receive_buffer,
+                  (size_t)max_bytes_to_read);
+               if (len == -1)
+               {
+                  log_error(LOG_LEVEL_ERROR, "Failed to receive data "
+                     "on client socket %d for an upgraded connection",
+                     csp->cfd);
+                  break;
+               }
+               if (len == 0)
+               {
+                  log_error(LOG_LEVEL_CONNECT, "Done receiving data "
+                     "on client socket %d for an upgraded connection",
+                     csp->cfd);
+                  break;
+               }
+               byte_count += (unsigned long long)len;
+               len = ssl_send_data(&(csp->ssl_server_attr),
+                  (unsigned char *)csp->receive_buffer, (size_t)len);
+               if (len == -1)
+               {
+                  log_error(LOG_LEVEL_ERROR, "Failed to send data "
+                     "on server socket %d for an upgraded connection",
+                     csp->server_connection.sfd);
+                  break;
+               }
+               continue;
+            }
             log_error(LOG_LEVEL_CONNECT, "Breaking with TLS/SSL.");
             break;
          }
@@ -2846,7 +2843,7 @@ static void handle_established_connection(struct client_state *csp)
                csp->expected_client_content_length -= (unsigned)len;
                log_error(LOG_LEVEL_CONNECT,
                   "Expected client content length set to %llu "
-                  "after reading %d bytes.",
+                  "after reading %ld bytes.",
                   csp->expected_client_content_length, len);
                if (csp->expected_client_content_length == 0)
                {
@@ -2872,11 +2869,7 @@ static void handle_established_connection(struct client_state *csp)
        * If `hdr' is null, then it's the header otherwise it's the body.
        * FIXME: Does `hdr' really mean `host'? No.
        */
-#ifdef HAVE_POLL
       if (poll_fds[1].revents != 0)
-#else
-      if (FD_ISSET(csp->server_connection.sfd, &rfds))
-#endif /* HAVE_POLL */
       {
 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
          /*
@@ -3320,7 +3313,7 @@ static void handle_established_connection(struct client_state *csp)
                    */
                   log_error(LOG_LEVEL_CONNECT,
                      "Continuing buffering server headers from socket %d. "
-                     "Bytes most recently read: %d.", csp->cfd, len);
+                     "Bytes most recently read: %ld.", csp->cfd, len);
                   continue;
                }
             }
@@ -3665,12 +3658,6 @@ static void chat(struct client_state *csp)
 
    /* decide how to route the HTTP request */
    fwd = forward_url(csp, http);
-   if (NULL == fwd)
-   {
-      log_error(LOG_LEVEL_FATAL, "gateway spec is NULL!?!?  This can't happen!");
-      /* Never get here - LOG_LEVEL_FATAL causes program exit */
-      return;
-   }
 
 #ifdef FEATURE_HTTPS_INSPECTION
    /*
@@ -4108,10 +4095,12 @@ static void chat(struct client_state *csp)
       else
       {
          /*
-          * If server certificate is invalid, we must inform client and then
-          * close connection with client.
+          * If server certificate has been verified and is invalid,
+          * we must inform the client and then close the connection
+          * with client and server.
           */
-         if (csp->server_cert_verification_result != SSL_CERT_VALID)
+         if (csp->server_cert_verification_result != SSL_CERT_VALID &&
+             csp->server_cert_verification_result != SSL_CERT_NOT_VERIFIED)
          {
             ssl_send_certificate_error(csp);
             close_client_and_server_ssl_connections(csp);
@@ -4259,7 +4248,7 @@ static void prepare_csp_for_next_request(struct client_state *csp)
       assert(bytes_to_shift > 0);
       assert(data_length > 0);
 
-      log_error(LOG_LEVEL_CONNECT, "Shifting %d pipelined bytes by %d bytes",
+      log_error(LOG_LEVEL_CONNECT, "Shifting %lu pipelined bytes by %ld bytes",
          data_length, bytes_to_shift);
       memmove(csp->client_iob->buf, csp->client_iob->cur, data_length);
       csp->client_iob->cur = csp->client_iob->buf;
@@ -4493,6 +4482,20 @@ static void serve(struct client_state *csp)
    chat(csp);
 #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
 
+   if (csp->cfd != JB_INVALID_SOCKET)
+   {
+      log_error(LOG_LEVEL_CONNECT, "Closing client socket %d. "
+         "Keep-alive: %u. Socket alive: %u. Data available: %u. "
+         "Configuration file change detected: %u. Requests received: %u.",
+         csp->cfd, 0 != (csp->flags & CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE),
+         socket_is_still_alive(csp->cfd), data_is_available(csp->cfd, 0),
+         config_file_change_detected, csp->requests_received_total);
+#ifdef FEATURE_HTTPS_INSPECTION
+      close_client_ssl_connection(csp);
+#endif
+      drain_and_close_socket(csp->cfd);
+   }
+
    if (csp->server_connection.sfd != JB_INVALID_SOCKET)
    {
 #ifdef FEATURE_CONNECTION_SHARING
@@ -4513,20 +4516,6 @@ static void serve(struct client_state *csp)
    mark_connection_closed(&csp->server_connection);
 #endif
 
-   if (csp->cfd != JB_INVALID_SOCKET)
-   {
-      log_error(LOG_LEVEL_CONNECT, "Closing client socket %d. "
-         "Keep-alive: %u. Socket alive: %u. Data available: %u. "
-         "Configuration file change detected: %u. Requests received: %u.",
-         csp->cfd, 0 != (csp->flags & CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE),
-         socket_is_still_alive(csp->cfd), data_is_available(csp->cfd, 0),
-         config_file_change_detected, csp->requests_received_total);
-#ifdef FEATURE_HTTPS_INSPECTION
-      close_client_ssl_connection(csp);
-#endif
-      drain_and_close_socket(csp->cfd);
-   }
-
    free_csp_resources(csp);
 
    csp->flags &= ~CSP_FLAG_ACTIVE;
@@ -5310,17 +5299,6 @@ static jb_socket bind_port_helper(const char *haddr, int hport, int backlog)
       return JB_INVALID_SOCKET;
    }
 
-#ifndef HAVE_POLL
-#ifndef _WIN32
-   if (bfd >= FD_SETSIZE)
-   {
-      log_error(LOG_LEVEL_FATAL,
-         "Bind socket number too high to use select(): %d >= %d",
-         bfd, FD_SETSIZE);
-   }
-#endif
-#endif
-
    if (haddr == NULL)
    {
       log_error(LOG_LEVEL_INFO, "Listening on port %d on all IP addresses",
@@ -5502,7 +5480,7 @@ static void listen_loop(void)
       csp = &csp_list->csp;
 
       log_error(LOG_LEVEL_CONNECT,
-         "Waiting for the next client connection. Currently active threads: %d",
+         "Waiting for the next client connection. Currently active threads: %u",
          active_threads);
 
       /*
@@ -5719,7 +5697,7 @@ static void listen_loop(void)
              * XXX: If you assume ...
              */
             log_error(LOG_LEVEL_ERROR,
-               "Unable to take any additional connections: %E. Active threads: %d",
+               "Unable to take any additional connections: %E. Active threads: %u",
                active_threads);
             write_socket_delayed(csp->cfd, TOO_MANY_CONNECTIONS_RESPONSE,
                strlen(TOO_MANY_CONNECTIONS_RESPONSE), get_write_delay(csp));