X-Git-Url: http://www.privoxy.org/gitweb/?p=privoxy.git;a=blobdiff_plain;f=jcc.c;h=722d7fd1d53e4371d2a7181797d2817673eaa3a9;hp=7a23ea66c7853d1257eec0969ec8e9e605842b93;hb=2c9ada84c1fd80a9d0afd7d29e16874d50cdffcf;hpb=a9020a996f608a81d1f894e6c854c1e6edd485d7 diff --git a/jcc.c b/jcc.c index 7a23ea66..722d7fd1 100644 --- a/jcc.c +++ b/jcc.c @@ -1,4 +1,4 @@ -const char jcc_rcs[] = "$Id: jcc.c,v 1.295 2009/09/26 13:32:35 fabiankeil Exp $"; +const char jcc_rcs[] = "$Id: jcc.c,v 1.319 2010/05/24 11:40:27 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/jcc.c,v $ @@ -6,7 +6,7 @@ const char jcc_rcs[] = "$Id: jcc.c,v 1.295 2009/09/26 13:32:35 fabiankeil Exp $" * Purpose : Main file. Contains main() method, main loop, and * the main connection-handling function. * - * Copyright : Written by and Copyright (C) 2001-2009 the SourceForge + * Copyright : Written by and Copyright (C) 2001-2010 the * Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written @@ -119,7 +119,7 @@ const char jcc_rcs[] = "$Id: jcc.c,v 1.295 2009/09/26 13:32:35 fabiankeil Exp $" const char jcc_h_rcs[] = JCC_H_VERSION; const char project_h_rcs[] = PROJECT_H_VERSION; -int no_daemon = 0; +int daemon_mode = 1; struct client_state clients[1]; struct file_list files[1]; @@ -625,39 +625,39 @@ static const char *crunch_reason(const struct http_response *rsp) return "Internal error while searching for crunch reason"; } - switch (rsp->reason) + switch (rsp->crunch_reason) { - case RSP_REASON_UNSUPPORTED: + case UNSUPPORTED: reason = "Unsupported HTTP feature"; break; - case RSP_REASON_BLOCKED: + case BLOCKED: reason = "Blocked"; break; - case RSP_REASON_UNTRUSTED: + case UNTRUSTED: reason = "Untrusted"; break; - case RSP_REASON_REDIRECTED: + case REDIRECTED: reason = "Redirected"; break; - case RSP_REASON_CGI_CALL: + case CGI_CALL: reason = "CGI Call"; break; - case RSP_REASON_NO_SUCH_DOMAIN: + case NO_SUCH_DOMAIN: reason = "DNS failure"; break; - case RSP_REASON_FORWARDING_FAILED: + case FORWARDING_FAILED: reason = "Forwarding failed"; break; - case RSP_REASON_CONNECT_FAILED: + case CONNECT_FAILED: reason = "Connection failure"; break; - case RSP_REASON_OUT_OF_MEMORY: + case OUT_OF_MEMORY: reason = "Out of memory (may mask other reasons)"; break; - case RSP_REASON_CONNECTION_TIMEOUT: + case CONNECTION_TIMEOUT: reason = "Connection timeout"; break; - case RSP_REASON_NO_SERVER_DATA: + case NO_SERVER_DATA: reason = "No server data received"; break; default: @@ -694,24 +694,12 @@ static void send_crunch_response(const struct client_state *csp, struct http_res if (rsp == NULL) { - /* - * Not supposed to happen. If it does - * anyway, treat it as an unknown error. - */ - cgi_error_unknown(csp, rsp, RSP_REASON_INTERNAL_ERROR); - /* return code doesn't matter */ - } - - if (rsp == NULL) - { - /* If rsp is still NULL, we have serious internal problems. */ - log_error(LOG_LEVEL_FATAL, - "NULL response in send_crunch_response and cgi_error_unknown failed as well."); + log_error(LOG_LEVEL_FATAL, "NULL response in send_crunch_response."); } /* * Extract the status code from the actual head - * that was send to the client. It is the only + * that will be send to the client. It is the only * way to get it right for all requests, including * the fixed ones for out-of-memory problems. * @@ -724,19 +712,21 @@ static void send_crunch_response(const struct client_state *csp, struct http_res status_code[2] = rsp->head[11]; status_code[3] = '\0'; + /* Log that the request was crunched and why. */ + log_error(LOG_LEVEL_CRUNCH, "%s: %s", crunch_reason(rsp), http->url); + log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" %s %u", + csp->ip_addr_str, http->ocmd, status_code, rsp->content_length); + /* Write the answer to the client */ if (write_socket(csp->cfd, rsp->head, rsp->head_length) || write_socket(csp->cfd, rsp->body, rsp->content_length)) { /* There is nothing we can do about it. */ - log_error(LOG_LEVEL_ERROR, "write to: %s failed: %E", csp->http->host); + log_error(LOG_LEVEL_ERROR, + "Couldn't deliver the error message through client socket %d: %E", + csp->cfd); } - /* Log that the request was crunched and why. */ - log_error(LOG_LEVEL_CRUNCH, "%s: %s", crunch_reason(rsp), http->url); - log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" %s %u", - csp->ip_addr_str, http->ocmd, status_code, rsp->content_length); - /* Clean up and return */ if (cgi_error_memory() != rsp) { @@ -838,6 +828,7 @@ static int crunch_response_triggered(struct client_state *csp, const struct crun { /* Deliver, log and free the interception response. */ send_crunch_response(csp, rsp); + csp->flags |= CSP_FLAG_CRUNCHED; return TRUE; } @@ -857,6 +848,7 @@ static int crunch_response_triggered(struct client_state *csp, const struct crun { /* Deliver, log and free the interception response. */ send_crunch_response(csp, rsp); + csp->flags |= CSP_FLAG_CRUNCHED; #ifdef FEATURE_STATISTICS if (c->flags & CF_COUNT_AS_REJECT) { @@ -1235,7 +1227,8 @@ static void mark_server_socket_tainted(struct client_state *csp) && !(csp->flags |= CSP_FLAG_SERVER_SOCKET_TAINTED)) { log_error(LOG_LEVEL_CONNECT, - "Marking the server socket %d tainted.", csp->sfd); + "Marking the server socket %d tainted.", + csp->server_connection.sfd); csp->flags |= CSP_FLAG_SERVER_SOCKET_TAINTED; } } @@ -1264,8 +1257,9 @@ static char *get_request_line(struct client_state *csp) { if (!data_is_available(csp->cfd, csp->config->socket_timeout)) { - log_error(LOG_LEVEL_ERROR, - "Stopped waiting for the request line."); + log_error(LOG_LEVEL_CONNECT, + "Stopped waiting for the request line. Timeout: %d.", + csp->config->socket_timeout); write_socket(csp->cfd, CLIENT_CONNECTION_TIMEOUT_RESPONSE, strlen(CLIENT_CONNECTION_TIMEOUT_RESPONSE)); return NULL; @@ -1563,11 +1557,16 @@ static jb_err parse_client_request(struct client_state *csp) * * Function : chat * - * Description : Once a connection to the client has been accepted, + * Description : Once a connection from the client has been accepted, * this function is called (via serve()) to handle the - * main business of the communication. When this - * function returns, the caller must close the client - * socket handle. + * main business of the communication. This function + * returns after dealing with a single request. It can + * be called multiple times witht the same client socket + * if the client is keeping the connection alive. + * + * The decision whether or not a client connection will + * be kept alive is up to the caller which also must + * close the client socket when done. * * FIXME: chat is nearly thousand lines long. * Ridiculous. @@ -1601,7 +1600,9 @@ static void chat(struct client_state *csp) /* Skeleton for HTTP response, if we should intercept the request */ struct http_response *rsp; struct timeval timeout; +#ifdef FEATURE_CONNECTION_KEEP_ALIVE int watch_client_socket = 1; +#endif memset(buf, 0, sizeof(buf)); @@ -1710,27 +1711,27 @@ static void chat(struct client_state *csp) /* here we connect to the server, gateway, or the forwarder */ #ifdef FEATURE_CONNECTION_KEEP_ALIVE - if ((csp->sfd != JB_INVALID_SOCKET) - && socket_is_still_usable(csp->sfd) + if ((csp->server_connection.sfd != JB_INVALID_SOCKET) + && socket_is_still_alive(csp->server_connection.sfd) && connection_destination_matches(&csp->server_connection, http, fwd)) { log_error(LOG_LEVEL_CONNECT, "Reusing server socket %u. Opened for %s.", - csp->sfd, csp->server_connection.host); + csp->server_connection.sfd, csp->server_connection.host); } else { - if (csp->sfd != JB_INVALID_SOCKET) + if (csp->server_connection.sfd != JB_INVALID_SOCKET) { log_error(LOG_LEVEL_CONNECT, "Closing server socket %u. Opened for %s.", - csp->sfd, csp->server_connection.host); - close_socket(csp->sfd); + csp->server_connection.sfd, csp->server_connection.host); + close_socket(csp->server_connection.sfd); mark_connection_closed(&csp->server_connection); } #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ - while ((csp->sfd = forwarded_connect(fwd, http, csp)) + while ((csp->server_connection.sfd = forwarded_connect(fwd, http, csp)) && (errno == EINVAL) && (forwarded_connect_retries++ < max_forwarded_connect_retries)) { @@ -1739,7 +1740,7 @@ static void chat(struct client_state *csp) forwarded_connect_retries, http->hostport); } - if (csp->sfd == JB_INVALID_SOCKET) + if (csp->server_connection.sfd == JB_INVALID_SOCKET) { if (fwd->type != SOCKS_NONE) { @@ -1766,8 +1767,10 @@ static void chat(struct client_state *csp) return; } #ifdef FEATURE_CONNECTION_KEEP_ALIVE - save_connection_destination(csp->sfd, http, fwd, &csp->server_connection); - csp->server_connection.keep_alive_timeout = (unsigned)csp->config->keep_alive_timeout; + save_connection_destination(csp->server_connection.sfd, + http, fwd, &csp->server_connection); + csp->server_connection.keep_alive_timeout = + (unsigned)csp->config->keep_alive_timeout; } #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ @@ -1785,8 +1788,8 @@ static void chat(struct client_state *csp) * Write the client's (modified) header to the server * (along with anything else that may be in the buffer) */ - if (write_socket(csp->sfd, hdr, strlen(hdr)) - || (flush_socket(csp->sfd, csp->iob) < 0)) + if (write_socket(csp->server_connection.sfd, hdr, strlen(hdr)) + || (flush_socket(csp->server_connection.sfd, csp->iob) < 0)) { log_error(LOG_LEVEL_CONNECT, "write header to: %s failed: %E", http->hostport); @@ -1823,7 +1826,8 @@ static void chat(struct client_state *csp) /* we're finished with the client's header */ freez(hdr); - maxfd = (csp->cfd > csp->sfd) ? csp->cfd : csp->sfd; + maxfd = (csp->cfd > csp->server_connection.sfd) ? + csp->cfd : csp->server_connection.sfd; /* pass data between the client and server * until one or the other shuts down the connection. @@ -1845,7 +1849,7 @@ static void chat(struct client_state *csp) #ifdef FEATURE_CONNECTION_KEEP_ALIVE if (!watch_client_socket) { - maxfd = csp->sfd; + maxfd = csp->server_connection.sfd; } else #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ @@ -1853,7 +1857,7 @@ static void chat(struct client_state *csp) FD_SET(csp->cfd, &rfds); } - FD_SET(csp->sfd, &rfds); + FD_SET(csp->server_connection.sfd, &rfds); #ifdef FEATURE_CONNECTION_KEEP_ALIVE if ((csp->flags & CSP_FLAG_CHUNKED) @@ -1948,8 +1952,10 @@ static void chat(struct client_state *csp) * available on the socket, the client went fishing * and continuing talking to the server makes no sense. */ - log_error(LOG_LEVEL_CONNECT, "The client closed socket %d while " - "the server socket %d is still open.", csp->cfd, csp->sfd); + log_error(LOG_LEVEL_CONNECT, + "The client closed socket %d while " + "the server socket %d is still open.", + csp->cfd, csp->server_connection.sfd); mark_server_socket_tainted(csp); break; } @@ -1993,7 +1999,7 @@ static void chat(struct client_state *csp) } #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ - if (write_socket(csp->sfd, buf, (size_t)len)) + if (write_socket(csp->server_connection.sfd, buf, (size_t)len)) { log_error(LOG_LEVEL_ERROR, "write to: %s failed: %E", http->host); mark_server_socket_tainted(csp); @@ -2007,10 +2013,10 @@ static void chat(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. */ - if (FD_ISSET(csp->sfd, &rfds)) + if (FD_ISSET(csp->server_connection.sfd, &rfds)) { #ifdef FEATURE_CONNECTION_KEEP_ALIVE - if (!socket_is_still_usable(csp->cfd)) + if (!socket_is_still_alive(csp->cfd)) { #ifdef _WIN32 log_error(LOG_LEVEL_CONNECT, @@ -2025,7 +2031,7 @@ static void chat(struct client_state *csp) #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ fflush(NULL); - len = read_socket(csp->sfd, buf, sizeof(buf) - 1); + len = read_socket(csp->server_connection.sfd, buf, sizeof(buf) - 1); if (len < 0) { @@ -2304,10 +2310,21 @@ static void chat(struct client_state *csp) /* Did we actually get anything? */ if (NULL == csp->headers->first) { - log_error(LOG_LEVEL_ERROR, - "Empty server or forwarder response received on socket %d.", csp->sfd); + if ((csp->flags & CSP_FLAG_REUSED_CLIENT_CONNECTION)) + { + log_error(LOG_LEVEL_ERROR, + "Empty server or forwarder response received on socket %d. " + "Closing client socket %d without sending data.", + csp->server_connection.sfd, csp->cfd); + } + else + { + log_error(LOG_LEVEL_ERROR, + "Empty server or forwarder response received on socket %d.", + csp->server_connection.sfd); + send_crunch_response(csp, error_response(csp, "no-server-data")); + } log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 502 0", csp->ip_addr_str, http->cmd); - send_crunch_response(csp, error_response(csp, "no-server-data")); free_http_request(http); mark_server_socket_tainted(csp); return; @@ -2455,6 +2472,46 @@ static void chat(struct client_state *csp) } +#ifdef FEATURE_CONNECTION_KEEP_ALIVE +/********************************************************************* + * + * Function : prepare_csp_for_next_request + * + * Description : Put the csp in a mostly vergin state. + * + * Parameters : + * 1 : csp = Current client state (buffers, headers, etc...) + * + * Returns : N/A + * + *********************************************************************/ +static void prepare_csp_for_next_request(struct client_state *csp) +{ + csp->content_type = 0; + csp->content_length = 0; + csp->expected_content_length = 0; + csp->expected_client_content_length = 0; + list_remove_all(csp->headers); + freez(csp->iob->buf); + memset(csp->iob, 0, sizeof(csp->iob)); + freez(csp->error_message); + free_http_request(csp->http); + destroy_list(csp->headers); + destroy_list(csp->tags); + free_current_action(csp->action); + if (NULL != csp->fwd) + { + unload_forward_spec(csp->fwd); + csp->fwd = NULL; + } + /* XXX: Store per-connection flags someplace else. */ + csp->flags &= CSP_FLAG_TOGGLED_ON; + csp->flags |= CSP_FLAG_ACTIVE; + csp->flags |= CSP_FLAG_REUSED_CLIENT_CONNECTION; +} +#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ + + /********************************************************************* * * Function : serve @@ -2487,74 +2544,73 @@ static void serve(struct client_state *csp) chat(csp); + /* + * If the request has been crunched, + * the calculated latency is zero. + */ latency = (unsigned)(csp->server_connection.response_received - csp->server_connection.request_sent) / 2; continue_chatting = (csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE) - && (csp->flags & CSP_FLAG_SERVER_CONNECTION_KEEP_ALIVE) - && !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED) - && (csp->cfd != JB_INVALID_SOCKET) - && (csp->sfd != JB_INVALID_SOCKET) - && socket_is_still_usable(csp->sfd) - && (latency < csp->server_connection.keep_alive_timeout); + && (((csp->flags & CSP_FLAG_SERVER_CONNECTION_KEEP_ALIVE) + && !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED)) + || (csp->flags & CSP_FLAG_CRUNCHED)) + && (csp->cfd != JB_INVALID_SOCKET); + + if (continue_chatting && !(csp->flags & CSP_FLAG_CRUNCHED)) + { + continue_chatting = (csp->server_connection.sfd != JB_INVALID_SOCKET) + && socket_is_still_alive(csp->server_connection.sfd); + if (continue_chatting) + { + if (!(csp->flags & CSP_FLAG_SERVER_KEEP_ALIVE_TIMEOUT_SET)) + { + csp->server_connection.keep_alive_timeout = csp->config->default_server_timeout; + log_error(LOG_LEVEL_CONNECT, + "The server didn't specify how long the connection will stay open. " + "Assumed timeout is: %u.", csp->server_connection.keep_alive_timeout); + } + continue_chatting = (latency < csp->server_connection.keep_alive_timeout); + } + } if (continue_chatting) { unsigned int client_timeout; - if (!(csp->flags & CSP_FLAG_SERVER_KEEP_ALIVE_TIMEOUT_SET)) + if (csp->server_connection.sfd != JB_INVALID_SOCKET) { - log_error(LOG_LEVEL_CONNECT, "The server didn't specify how long " - "the connection will stay open. Assume it's only a second."); - csp->server_connection.keep_alive_timeout = 1; + client_timeout = (unsigned)csp->server_connection.keep_alive_timeout - latency; + log_error(LOG_LEVEL_CONNECT, + "Waiting for the next client request on socket %d. " + "Keeping the server socket %d to %s open.", + csp->cfd, csp->server_connection.sfd, csp->server_connection.host); + } + else + { + client_timeout = 1; /* XXX: Use something else here? */ + log_error(LOG_LEVEL_CONNECT, + "Waiting for the next client request on socket %d. " + "No server socket to keep open.", csp->cfd); } - - client_timeout = (unsigned)csp->server_connection.keep_alive_timeout - latency; - - log_error(LOG_LEVEL_CONNECT, - "Waiting for the next client request. " - "Keeping the server socket %d to %s open.", - csp->sfd, csp->server_connection.host); - if ((csp->flags & CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE) && data_is_available(csp->cfd, (int)client_timeout) - && socket_is_still_usable(csp->cfd)) + && socket_is_still_alive(csp->cfd)) { log_error(LOG_LEVEL_CONNECT, "Client request arrived in " - "time or the client closed the connection."); - /* - * Get the csp in a mostly vergin state again. - * XXX: Should be done elsewhere. - */ - csp->content_type = 0; - csp->content_length = 0; - csp->expected_content_length = 0; - csp->expected_client_content_length = 0; - list_remove_all(csp->headers); - freez(csp->iob->buf); - memset(csp->iob, 0, sizeof(csp->iob)); - freez(csp->error_message); - free_http_request(csp->http); - destroy_list(csp->headers); - destroy_list(csp->tags); - free_current_action(csp->action); - if (NULL != csp->fwd) - { - unload_forward_spec(csp->fwd); - csp->fwd = NULL; - } - - /* XXX: Store per-connection flags someplace else. */ - csp->flags = CSP_FLAG_ACTIVE | (csp->flags & CSP_FLAG_TOGGLED_ON); + "time or the client closed the connection on socket %d.", + csp->cfd); + prepare_csp_for_next_request(csp); } else { log_error(LOG_LEVEL_CONNECT, - "No additional client request received in time."); + "No additional client request received in time on socket %d.", + csp->cfd); #ifdef FEATURE_CONNECTION_SHARING if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_SHARING) - && (socket_is_still_usable(csp->sfd))) + && (socket_is_still_alive(csp->server_connection.sfd))) { time_t time_open = time(NULL) - csp->server_connection.timestamp; @@ -2563,8 +2619,8 @@ static void serve(struct client_state *csp) break; } - remember_connection(csp, forward_url(csp, csp->http)); - csp->sfd = JB_INVALID_SOCKET; + remember_connection(&csp->server_connection); + csp->server_connection.sfd = JB_INVALID_SOCKET; close_socket(csp->cfd); csp->cfd = JB_INVALID_SOCKET; privoxy_mutex_lock(&connection_reuse_mutex); @@ -2582,27 +2638,33 @@ static void serve(struct client_state *csp) break; } } - else if (csp->sfd != JB_INVALID_SOCKET) + else if (csp->server_connection.sfd != JB_INVALID_SOCKET) { log_error(LOG_LEVEL_CONNECT, "The connection on server socket %d to %s isn't reusable. " - "Closing.", csp->sfd, csp->server_connection.host); + "Closing.", csp->server_connection.sfd, csp->server_connection.host); } } while (continue_chatting); - mark_connection_closed(&csp->server_connection); #else chat(csp); #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ - if (csp->sfd != JB_INVALID_SOCKET) + if (csp->server_connection.sfd != JB_INVALID_SOCKET) { #ifdef FEATURE_CONNECTION_SHARING - forget_connection(csp->sfd); + if (csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_SHARING) + { + forget_connection(csp->server_connection.sfd); + } #endif /* def FEATURE_CONNECTION_SHARING */ - close_socket(csp->sfd); + close_socket(csp->server_connection.sfd); } +#ifdef FEATURE_CONNECTION_KEEP_ALIVE + mark_connection_closed(&csp->server_connection); +#endif + if (csp->cfd != JB_INVALID_SOCKET) { close_socket(csp->cfd); @@ -2917,7 +2979,7 @@ int main(int argc, char **argv) else if (strcmp(argv[argc_pos], "--no-daemon" ) == 0) { set_debug_level(LOG_LEVEL_FATAL | LOG_LEVEL_ERROR | LOG_LEVEL_INFO); - no_daemon = 1; + daemon_mode = 0; } else if (strcmp(argv[argc_pos], "--pidfile" ) == 0) @@ -3083,14 +3145,10 @@ int main(int argc, char **argv) */ #if defined(unix) { - pid_t pid = 0; -#if 0 - int fd; -#endif - - if (!no_daemon) + if (daemon_mode) { - pid = fork(); + int fd; + pid_t pid = fork(); if ( pid < 0 ) /* error */ { @@ -3114,33 +3172,50 @@ int main(int argc, char **argv) exit( 0 ); } /* child */ -#if 1 - /* Should be more portable, but not as well tested */ + setsid(); -#else /* !1 */ -#ifdef __FreeBSD__ - setpgrp(0,0); -#else /* ndef __FreeBSD__ */ - setpgrp(); -#endif /* ndef __FreeBSD__ */ - fd = open("/dev/tty", O_RDONLY); - if ( fd ) - { - /* no error check here */ - ioctl( fd, TIOCNOTTY,0 ); - close ( fd ); - } -#endif /* 1 */ + /* * stderr (fd 2) will be closed later on, * when the config file has been parsed. */ + close(0); + close(1); + + /* + * Reserve fd 0 and 1 to prevent abort() and friends + * from sending stuff to the clients or servers. + */ + fd = open("/dev/null", O_RDONLY); + if (fd == -1) + { + log_error(LOG_LEVEL_FATAL, "Failed to open /dev/null: %E"); + } + else if (fd != 0) + { + if (dup2(fd, 0) == -1) + { + log_error(LOG_LEVEL_FATAL, "Failed to reserve fd 0: %E"); + } + close(fd); + } + fd = open("/dev/null", O_WRONLY); + if (fd == -1) + { + log_error(LOG_LEVEL_FATAL, "Failed to open /dev/null: %E"); + } + else if (fd != 1) + { + if (dup2(fd, 1) == -1) + { + log_error(LOG_LEVEL_FATAL, "Failed to reserve fd 1: %E"); + } + close(fd); + } - close( 0 ); - close( 1 ); chdir("/"); - } /* -END- if (!no_daemon) */ + } /* -END- if (daemon_mode) */ /* * As soon as we have written the PID file, we can switch @@ -3398,7 +3473,7 @@ static void listen_loop(void) } csp->flags |= CSP_FLAG_ACTIVE; - csp->sfd = JB_INVALID_SOCKET; + csp->server_connection.sfd = JB_INVALID_SOCKET; csp->config = config = load_config();