X-Git-Url: http://www.privoxy.org/gitweb/?p=privoxy.git;a=blobdiff_plain;f=jcc.c;h=fdcd69b83c154385cac0354d26fa5c07219e384a;hp=0dc75335ad7bdcadaa03070fec4af2d114076586;hb=2380f2ad52748713f50ffb0ab10613204a58accd;hpb=05b18a8cb1864e52703997c92c6831356ee2fa1c diff --git a/jcc.c b/jcc.c index 0dc75335..fdcd69b8 100644 --- a/jcc.c +++ b/jcc.c @@ -1,4 +1,4 @@ -const char jcc_rcs[] = "$Id: jcc.c,v 1.458 2017/05/29 10:02:11 fabiankeil Exp $"; +const char jcc_rcs[] = "$Id: jcc.c,v 1.469 2017/08/12 09:36:42 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/jcc.c,v $ @@ -105,6 +105,7 @@ const char jcc_rcs[] = "$Id: jcc.c,v 1.458 2017/05/29 10:02:11 fabiankeil Exp $" # ifndef FD_ZERO # include # endif +#warning poll() appears to be unavailable. Your platform will become unsupported in the future. #endif /* HAVE_POLL */ #endif @@ -162,7 +163,7 @@ static void serve(struct client_state *csp); static void usage(const char *myname); #endif static void initialize_mutexes(void); -static jb_socket bind_port_helper(const char *haddr, int hport); +static jb_socket bind_port_helper(const char *haddr, int hport, int backlog); static void bind_ports_helper(struct configuration_spec *config, jb_socket sockets[]); static void close_ports_helper(jb_socket sockets[]); static void listen_loop(void); @@ -1852,6 +1853,10 @@ static jb_err parse_client_request(struct client_state *csp) } verify_request_length(csp); } + else + { + csp->flags |= CSP_FLAG_SERVER_SOCKET_TAINTED; + } #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ err = sed(csp, FILTER_CLIENT_HEADERS); @@ -1959,10 +1964,8 @@ static int send_http_request(struct client_state *csp) * Returns : Nothing. * *********************************************************************/ -static void handle_established_connection(struct client_state *csp, - const struct forward_spec *fwd) +static void handle_established_connection(struct client_state *csp) { - char *receive_buffer; char *hdr; char *p; int n; @@ -1985,10 +1988,10 @@ static void handle_established_connection(struct client_state *csp, #ifdef FEATURE_CONNECTION_KEEP_ALIVE int watch_client_socket; #endif - const size_t receive_buffer_size = csp->config->receive_buffer_size; - receive_buffer = zalloc(receive_buffer_size + 1); - if (receive_buffer == NULL) + csp->receive_buffer_size = csp->config->receive_buffer_size; + csp->receive_buffer = zalloc(csp->receive_buffer_size + 1); + if (csp->receive_buffer == NULL) { log_error(LOG_LEVEL_ERROR, "Out of memory. Failed to allocate the receive buffer."); @@ -2112,14 +2115,13 @@ static void handle_established_connection(struct client_state *csp, if (n == 0) { - log_error(LOG_LEVEL_ERROR, - "Didn't receive data in time: %s", http->url); + log_error(LOG_LEVEL_CONNECT, "Socket timeout %d reached: %s", + csp->config->socket_timeout, http->url); if ((byte_count == 0) && (http->ssl == 0)) { send_crunch_response(csp, error_response(csp, "connection-timeout")); } mark_server_socket_tainted(csp); - freez(receive_buffer); return; } else if (n < 0) @@ -2130,7 +2132,6 @@ static void handle_established_connection(struct client_state *csp, log_error(LOG_LEVEL_ERROR, "select() failed!: %E"); #endif mark_server_socket_tainted(csp); - freez(receive_buffer); return; } @@ -2157,7 +2158,7 @@ static void handle_established_connection(struct client_state *csp, if (FD_ISSET(csp->cfd, &rfds)) #endif /* def HAVE_POLL*/ { - int max_bytes_to_read = (int)receive_buffer_size; + int max_bytes_to_read = (int)csp->receive_buffer_size; #ifdef FEATURE_CONNECTION_KEEP_ALIVE if ((csp->flags & CSP_FLAG_CLIENT_REQUEST_COMPLETELY_READ)) @@ -2191,7 +2192,7 @@ static void handle_established_connection(struct client_state *csp, } if (csp->expected_client_content_length != 0) { - if (csp->expected_client_content_length < receive_buffer_size) + if (csp->expected_client_content_length < csp->receive_buffer_size) { max_bytes_to_read = (int)csp->expected_client_content_length; } @@ -2199,10 +2200,10 @@ static void handle_established_connection(struct client_state *csp, "Waiting for up to %d bytes from the client.", max_bytes_to_read); } - assert(max_bytes_to_read <= receive_buffer_size); + assert(max_bytes_to_read <= csp->receive_buffer_size); #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ - len = read_socket(csp->cfd, receive_buffer, max_bytes_to_read); + len = read_socket(csp->cfd, csp->receive_buffer, max_bytes_to_read); if (len <= 0) { @@ -2229,11 +2230,10 @@ static void handle_established_connection(struct client_state *csp, } #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ - if (write_socket(csp->server_connection.sfd, receive_buffer, (size_t)len)) + if (write_socket(csp->server_connection.sfd, csp->receive_buffer, (size_t)len)) { log_error(LOG_LEVEL_ERROR, "write to: %s failed: %E", http->host); mark_server_socket_tainted(csp); - freez(receive_buffer); return; } continue; @@ -2267,19 +2267,18 @@ static void handle_established_connection(struct client_state *csp, log_error(LOG_LEVEL_CONNECT, "The server still wants to talk, but the client hung up on us."); mark_server_socket_tainted(csp); - freez(receive_buffer); return; #endif /* def _WIN32 */ } #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ - len = read_socket(csp->server_connection.sfd, receive_buffer, (int)receive_buffer_size); + len = read_socket(csp->server_connection.sfd, csp->receive_buffer, (int)csp->receive_buffer_size); if (len < 0) { log_error(LOG_LEVEL_ERROR, "read from: %s failed: %E", http->host); - if (http->ssl && (fwd->forward_host == NULL)) + if (http->ssl && (csp->fwd == NULL)) { /* * Just hang up. We already confirmed the client's CONNECT @@ -2288,7 +2287,6 @@ static void handle_established_connection(struct client_state *csp, */ log_error(LOG_LEVEL_ERROR, "CONNECT already confirmed. Unable to tell the client about the problem."); - freez(receive_buffer); return; } else if (byte_count) @@ -2303,7 +2301,6 @@ static void handle_established_connection(struct client_state *csp, log_error(LOG_LEVEL_ERROR, "Already forwarded the original headers. " "Unable to tell the client about the problem."); mark_server_socket_tainted(csp); - freez(receive_buffer); return; } /* @@ -2316,7 +2313,7 @@ static void handle_established_connection(struct client_state *csp, #ifdef FEATURE_CONNECTION_KEEP_ALIVE if (csp->flags & CSP_FLAG_CHUNKED) { - if ((len >= 5) && !memcmp(receive_buffer+len-5, "0\r\n\r\n", 5)) + if ((len >= 5) && !memcmp(csp->receive_buffer+len-5, "0\r\n\r\n", 5)) { /* XXX: this is a temporary hack */ log_error(LOG_LEVEL_CONNECT, @@ -2333,19 +2330,19 @@ static void handle_established_connection(struct client_state *csp, * This is guaranteed by allocating with zalloc_or_die() * and never (intentionally) writing to the last byte. * - * receive_buffer_size is the size of the part of the + * csp->receive_buffer_size is the size of the part of the * buffer we intentionally write to, but we actually - * allocated receive_buffer_size+1 bytes so the assertion + * allocated csp->receive_buffer_size+1 bytes so the assertion * stays within the allocated range. */ - assert(receive_buffer[receive_buffer_size] == '\0'); + assert(csp->receive_buffer[csp->receive_buffer_size] == '\0'); /* * Add a trailing zero to let be able to use string operations. * XXX: do we still need this with filter_popups gone? */ - assert(len <= receive_buffer_size); - receive_buffer[len] = '\0'; + assert(len <= csp->receive_buffer_size); + csp->receive_buffer[len] = '\0'; /* * Normally, this would indicate that we've read @@ -2424,7 +2421,6 @@ static void handle_established_connection(struct client_state *csp, freez(hdr); freez(p); mark_server_socket_tainted(csp); - freez(receive_buffer); return; } @@ -2439,8 +2435,8 @@ static void handle_established_connection(struct client_state *csp, * This is NOT the body, so * Let's pretend the server just sent us a blank line. */ - snprintf(receive_buffer, receive_buffer_size, "\r\n"); - len = (int)strlen(receive_buffer); + snprintf(csp->receive_buffer, csp->receive_buffer_size, "\r\n"); + len = (int)strlen(csp->receive_buffer); /* * Now, let the normal header parsing algorithm below do its @@ -2464,7 +2460,7 @@ static void handle_established_connection(struct client_state *csp, * has been reached, switch to non-filtering mode, i.e. make & write the * header, flush the iob and buf, and get out of the way. */ - if (add_to_iob(csp->iob, csp->config->buffer_limit, receive_buffer, len)) + if (add_to_iob(csp->iob, csp->config->buffer_limit, csp->receive_buffer, len)) { size_t hdrlen; long flushed; @@ -2483,20 +2479,18 @@ static void handle_established_connection(struct client_state *csp, rsp = cgi_error_memory(); send_crunch_response(csp, rsp); mark_server_socket_tainted(csp); - freez(receive_buffer); return; } hdrlen = strlen(hdr); if (write_socket(csp->cfd, hdr, hdrlen) || ((flushed = flush_socket(csp->cfd, csp->iob)) < 0) - || (write_socket(csp->cfd, receive_buffer, (size_t)len))) + || (write_socket(csp->cfd, csp->receive_buffer, (size_t)len))) { log_error(LOG_LEVEL_CONNECT, "Flush header and buffers to client failed: %E"); freez(hdr); mark_server_socket_tainted(csp); - freez(receive_buffer); return; } @@ -2513,11 +2507,10 @@ static void handle_established_connection(struct client_state *csp, } else { - if (write_socket(csp->cfd, receive_buffer, (size_t)len)) + if (write_socket(csp->cfd, csp->receive_buffer, (size_t)len)) { log_error(LOG_LEVEL_ERROR, "write to client failed: %E"); mark_server_socket_tainted(csp); - freez(receive_buffer); return; } } @@ -2531,13 +2524,12 @@ static void handle_established_connection(struct client_state *csp, * Buffer up the data we just read. If that fails, there's * little we can do but send our static out-of-memory page. */ - if (add_to_iob(csp->iob, csp->config->buffer_limit, receive_buffer, len)) + if (add_to_iob(csp->iob, csp->config->buffer_limit, csp->receive_buffer, len)) { log_error(LOG_LEVEL_ERROR, "Out of memory while looking for end of server headers."); rsp = cgi_error_memory(); send_crunch_response(csp, rsp); mark_server_socket_tainted(csp); - freez(receive_buffer); return; } @@ -2558,7 +2550,6 @@ static void handle_established_connection(struct client_state *csp, write_socket(csp->cfd, INVALID_SERVER_HEADERS_RESPONSE, strlen(INVALID_SERVER_HEADERS_RESPONSE)); mark_server_socket_tainted(csp); - freez(receive_buffer); return; } else @@ -2604,7 +2595,6 @@ static void handle_established_connection(struct client_state *csp, } free_http_request(http); mark_server_socket_tainted(csp); - freez(receive_buffer); return; } @@ -2645,7 +2635,6 @@ static void handle_established_connection(struct client_state *csp, strlen(INVALID_SERVER_HEADERS_RESPONSE)); free_http_request(http); mark_server_socket_tainted(csp); - freez(receive_buffer); return; } hdr = list_to_text(csp->headers); @@ -2678,10 +2667,9 @@ static void handle_established_connection(struct client_state *csp, * delivered the crunch response to the client * and are done here after cleaning up. */ - freez(hdr); - mark_server_socket_tainted(csp); - freez(receive_buffer); - return; + freez(hdr); + mark_server_socket_tainted(csp); + return; } /* Buffer and pcrs filter this if appropriate. */ @@ -2711,7 +2699,6 @@ static void handle_established_connection(struct client_state *csp, */ freez(hdr); mark_server_socket_tainted(csp); - freez(receive_buffer); return; } } @@ -2736,17 +2723,14 @@ static void handle_established_connection(struct client_state *csp, write_socket(csp->cfd, INVALID_SERVER_HEADERS_RESPONSE, strlen(INVALID_SERVER_HEADERS_RESPONSE)); mark_server_socket_tainted(csp); - freez(receive_buffer); return; } } continue; } mark_server_socket_tainted(csp); - freez(receive_buffer); return; /* huh? we should never get here */ } - freez(receive_buffer); if (csp->content_length == 0) { @@ -3027,7 +3011,8 @@ static void chat(struct client_state *csp) /* XXX: should the time start earlier for optimistically sent data? */ csp->server_connection.request_sent = time(NULL); - handle_established_connection(csp, fwd); + handle_established_connection(csp); + freez(csp->receive_buffer); } @@ -3064,6 +3049,7 @@ extern int fuzz_server_response(struct client_state *csp, char *fuzz_input_file) fuzz_input_file); } } + csp->fwd = &fwd; csp->content_type |= CT_GIF; csp->action->flags |= ACTION_DEANIMATE; csp->action->string[ACTION_STRING_DEANIMATE] = "last"; @@ -3084,7 +3070,8 @@ extern int fuzz_server_response(struct client_state *csp, char *fuzz_input_file) cgi_init_error_messages(); - handle_established_connection(csp, &fwd); + handle_established_connection(csp); + freez(csp->receive_buffer); return 0; } @@ -3382,6 +3369,8 @@ static void serve(struct client_state *csp) drain_and_close_socket(csp->cfd); } + free_csp_resources(csp); + csp->flags &= ~CSP_FLAG_ACTIVE; } @@ -4116,16 +4105,17 @@ int main(int argc, char **argv) * 1 : haddr = Host address to bind to. Use NULL to bind to * INADDR_ANY. * 2 : hport = Specifies port to bind to. + * 3 : backlog = Listen backlog. * * Returns : Port that was opened. * *********************************************************************/ -static jb_socket bind_port_helper(const char *haddr, int hport) +static jb_socket bind_port_helper(const char *haddr, int hport, int backlog) { int result; jb_socket bfd; - result = bind_port(haddr, hport, &bfd); + result = bind_port(haddr, hport, backlog, &bfd); if (result < 0) { @@ -4205,7 +4195,22 @@ static void bind_ports_helper(struct configuration_spec * config, { if (config->hport[i]) { - sockets[i] = bind_port_helper(config->haddr[i], config->hport[i]); + sockets[i] = bind_port_helper(config->haddr[i], + config->hport[i], config->listen_backlog); +#if defined(FEATURE_ACCEPT_FILTER) && defined(SO_ACCEPTFILTER) + if (config->enable_accept_filter && sockets[i] != JB_INVALID_SOCKET) + { + struct accept_filter_arg af_options; + bzero(&af_options, sizeof(af_options)); + strlcpy(af_options.af_name, "httpready", sizeof(af_options.af_name)); + if (setsockopt(sockets[i], SOL_SOCKET, SO_ACCEPTFILTER, &af_options, + sizeof(af_options))) + { + log_error(LOG_LEVEL_ERROR, + "Enabling accept filter for socket %d failed: %E", sockets[i]); + } + } +#endif } else { @@ -4274,6 +4279,12 @@ static void listen_loop(void) jb_socket bfds[MAX_LISTENING_SOCKETS]; struct configuration_spec *config; unsigned int active_threads = 0; +#if defined(FEATURE_PTHREAD) + pthread_attr_t attrs; + + pthread_attr_init(&attrs); + pthread_attr_setdetachstate(&attrs, PTHREAD_CREATE_DETACHED); +#endif config = load_config(); @@ -4361,7 +4372,7 @@ static void listen_loop(void) * new one. * * Which-ever is correct, we will serve 1 more page via the - * old settings. This should probably be a "show-proxy-args" + * old settings. This should probably be a "show-status" * request. This should not be a so common of an operation * that this will hurt people's feelings. */ @@ -4429,14 +4440,10 @@ static void listen_loop(void) #define SELECTED_ONE_OPTION { pthread_t the_thread; - pthread_attr_t attrs; - pthread_attr_init(&attrs); - pthread_attr_setdetachstate(&attrs, PTHREAD_CREATE_DETACHED); errno = pthread_create(&the_thread, &attrs, (void * (*)(void *))serve, csp); child_id = errno ? -1 : 0; - pthread_attr_destroy(&attrs); } #endif @@ -4601,6 +4608,10 @@ static void listen_loop(void) } } +#if defined(FEATURE_PTHREAD) + pthread_attr_destroy(&attrs); +#endif + /* NOTREACHED unless FEATURE_GRACEFUL_TERMINATION is defined */ /* Clean up. Aim: free all memory (no leaks) */