Changes with Apache 2.0.29-dev
+ *) Begin to abstract out the underlying transport layer.
+ The first step is to remove the socket from the conn_rec,
+ the server now lives in a context that is passed to the
+ core's input and output filters. This forces us to be very
+ careful when adding calls that use the socket directly,
+ because the socket isn't available in most locations.
+ [Ryan Bloom]
+
*) Really reset the MaxClients value in worker and threaded
when the configured value is not a multiple of the number
of threads per child. We said we did previously but we
*/
AP_DECLARE_HOOK(int,process_connection,(conn_rec *c))
+/**
+ */
+AP_DECLARE_HOOK(conn_rec *, create_connection,
+ (apr_pool_t *p, apr_socket_t *csd, int child_num))
+
+/* This is NOT staying here. It is necessary to quiet warnings
+ * while I would on the next patch. rbb
+ */
+
+AP_CORE_DECLARE(conn_rec *)ap_core_new_connection(apr_pool_t *p,
+ server_rec *server, apr_socket_t *inout,
+ core_net_rec *net, long id);
+
#ifdef __cplusplus
}
#endif
#include "apr_pools.h"
#include "apr_time.h"
#include "apr_network_io.h"
+#include "apr_buckets.h"
#include "pcreposix.h"
*/
#define AP_MAX_SENDFILE 16777216
-
/**
* Special Apache error codes. These are basically used
* in http_main.c so we can keep track of various errors.
/* Information about the connection itself */
- /** Connection to the client */
- apr_socket_t *client_socket;
-
- /* Who is the client? */
-
/** local address */
apr_sockaddr_t *local_addr;
/** remote address */
apr_sockaddr_t *remote_addr;
+
/** Client's IP address */
char *remote_ip;
/** Client's DNS name, if known. NULL if DNS hasn't been checked,
int limit_req_fields;
};
+typedef struct core_output_filter_ctx {
+ apr_bucket_brigade *b;
+ apr_pool_t *subpool; /* subpool of c->pool used for data saved after a
+ * request is finished
+ */
+ int subpool_has_stuff; /* anything in the subpool? */
+} core_output_filter_ctx_t;
+
+typedef struct core_filter_ctx {
+ apr_bucket_brigade *b;
+ int first_line;
+} core_ctx_t;
+
+typedef struct core_net_rec {
+ /** Connection to the client */
+ apr_socket_t *client_socket;
+
+ /** connection record */
+ conn_rec *c;
+
+ core_output_filter_ctx_t *out_ctx;
+ core_ctx_t *in_ctx;
+} core_net_rec;
+
/**
* Examine a field value (such as a media-/content-type) string and return
* it sans any parameters; e.g., strip off any ';charset=foo' and the like.
static apr_port_t http_port(const request_rec *r)
{ return DEFAULT_HTTP_PORT; }
-static int ap_pre_http_connection(conn_rec *c)
-{
- ap_add_input_filter("CORE_IN", NULL, NULL, c);
- ap_add_output_filter("CORE", NULL, NULL, c);
- return OK;
-}
-
static int ap_process_http_connection(conn_rec *c)
{
request_rec *r;
static void register_hooks(apr_pool_t *p)
{
- ap_hook_pre_connection(ap_pre_http_connection,NULL,NULL,
- APR_HOOK_REALLY_LAST);
ap_hook_process_connection(ap_process_http_connection,NULL,NULL,
APR_HOOK_REALLY_LAST);
ap_hook_map_to_storage(ap_send_http_trace,NULL,NULL,APR_HOOK_MIDDLE);
APR_HOOK_STRUCT(
APR_HOOK_LINK(pre_connection)
APR_HOOK_LINK(process_connection)
+ APR_HOOK_LINK(create_connection)
)
AP_IMPLEMENT_HOOK_RUN_ALL(int,pre_connection,(conn_rec *c),(c),OK,DECLINED)
AP_IMPLEMENT_HOOK_RUN_FIRST(int,process_connection,(conn_rec *c),(c),DECLINED)
+AP_IMPLEMENT_HOOK_RUN_FIRST(conn_rec *,create_connection,
+ (apr_pool_t *p, apr_socket_t *csd, int my_child_num),
+ (p, csd, my_child_num), NULL)
/*
* More machine-dependent networking gooo... on some systems,
apr_status_t rc;
apr_int32_t timeout;
apr_int32_t total_linger_time = 0;
- conn_rec *c = dummy;
+ core_net_rec *net = dummy;
- ap_update_child_status(AP_CHILD_THREAD_FROM_ID(c->id), SERVER_CLOSING, NULL);
+ ap_update_child_status(AP_CHILD_THREAD_FROM_ID(net->c->id), SERVER_CLOSING, NULL);
#ifdef NO_LINGCLOSE
- ap_flush_conn(c); /* just close it */
- apr_socket_close(c->client_socket);
+ ap_flush_conn(net->c); /* just close it */
+ apr_socket_close(net->client_socket);
return;
#endif
*/
/* Send any leftover data to the client, but never try to again */
- ap_flush_conn(c);
+ ap_flush_conn(net->c);
- if (c->aborted) {
- apr_socket_close(c->client_socket);
+ if (net->c->aborted) {
+ apr_socket_close(net->client_socket);
return APR_SUCCESS;
}
/* Shut down the socket for write, which will send a FIN
* to the peer.
*/
-
- if (apr_shutdown(c->client_socket, APR_SHUTDOWN_WRITE) != APR_SUCCESS ||
- c->aborted) {
- apr_socket_close(c->client_socket);
- return APR_SUCCESS;
+ if (apr_shutdown(net->client_socket, APR_SHUTDOWN_WRITE) != APR_SUCCESS ||
+ net->c->aborted) {
}
/* Read all data from the peer until we reach "end-of-file" (FIN
* which seems to work well), close the connection.
*/
timeout = SECONDS_TO_LINGER * APR_USEC_PER_SEC;
- apr_setsocketopt(c->client_socket, APR_SO_TIMEOUT, timeout);
- apr_setsocketopt(c->client_socket, APR_INCOMPLETE_READ, 1);
+ apr_setsocketopt(net->client_socket, APR_SO_TIMEOUT, timeout);
+ apr_setsocketopt(net->client_socket, APR_INCOMPLETE_READ, 1);
for (;;) {
nbytes = sizeof(dummybuf);
- rc = apr_recv(c->client_socket, dummybuf, &nbytes);
+ rc = apr_recv(net->client_socket, dummybuf, &nbytes);
if (rc != APR_SUCCESS || nbytes == 0) break;
total_linger_time += SECONDS_TO_LINGER;
}
}
- apr_socket_close(c->client_socket);
+ apr_socket_close(net->client_socket);
return APR_SUCCESS;
}
structure, but for now...
*/
-AP_CORE_DECLARE(conn_rec *)ap_new_connection(apr_pool_t *p, server_rec *server,
- apr_socket_t *inout, long id)
+AP_CORE_DECLARE(conn_rec *)ap_core_new_connection(apr_pool_t *p,
+ server_rec *server, apr_socket_t *inout,
+ core_net_rec *net, long id)
{
conn_rec *conn = (conn_rec *) apr_pcalloc(p, sizeof(conn_rec));
apr_status_t rv;
}
apr_sockaddr_ip_get(&conn->remote_ip, conn->remote_addr);
conn->base_server = server;
- conn->client_socket = inout;
+ net->client_socket = inout;
conn->id = id;
- apr_pool_cleanup_register(p, conn, ap_lingering_close, apr_pool_cleanup_null);
+ apr_pool_cleanup_register(p, net, ap_lingering_close, apr_pool_cleanup_null);
return conn;
}
#include "scoreboard.h"
#include "mod_core.h"
#include "mod_proxy.h"
-
+#include "ap_listen.h"
/* LimitXMLRequestBody handling */
#define AP_LIMIT_UNSET ((long) -1)
(apr_pool_t *p, const char *val, apr_hash_t *ht),
(p, val, ht), OK, DECLINED)
-
/* Server core module... This module provides support for really basic
* server operations, including options and commands which control the
* operation of other modules. Consider this the bureaucracy module.
&& conn->remote_host == NULL
&& (type == REMOTE_DOUBLE_REV
|| hostname_lookups != HOSTNAME_LOOKUP_OFF)) {
- apr_sockaddr_t *remote_addr;
- apr_socket_addr_get(&remote_addr, APR_REMOTE, conn->client_socket);
- if (apr_getnameinfo(&conn->remote_host, remote_addr, 0) == APR_SUCCESS) {
+ if (apr_getnameinfo(&conn->remote_host, conn->remote_addr, 0) == APR_SUCCESS) {
ap_str_tolower(conn->remote_host);
if (hostname_lookups == HOSTNAME_LOOKUP_DOUBLE) {
}
if (d->use_canonical_name == USE_CANONICAL_NAME_DNS) {
if (conn->local_host == NULL) {
- apr_sockaddr_t *local_addr;
- apr_socket_addr_get(&local_addr, APR_LOCAL, conn->client_socket);
- if (apr_getnameinfo(&conn->local_host, local_addr, 0) != APR_SUCCESS)
+ if (apr_getnameinfo(&conn->local_host, conn->local_addr, 0) != APR_SUCCESS)
conn->local_host = apr_pstrdup(conn->pool, r->server->server_hostname);
else {
ap_str_tolower(conn->local_host);
*/
#if APR_HAS_SENDFILE
-static apr_status_t sendfile_it_all(conn_rec *c,
+static apr_status_t sendfile_it_all(core_net_rec *c,
apr_file_t *fd,
apr_hdtr_t *hdtr,
apr_off_t file_offset,
* to the network. emulate_sendfile will return only when all the bytes have been
* sent (i.e., it handles partial writes) or on a network error condition.
*/
-static apr_status_t emulate_sendfile(conn_rec *c, apr_file_t *fd,
+static apr_status_t emulate_sendfile(core_net_rec *c, apr_file_t *fd,
apr_hdtr_t *hdtr, apr_off_t offset,
apr_size_t length, apr_size_t *nbytes)
{
return ap_pass_brigade(r->output_filters, bb);
}
-typedef struct core_filter_ctx {
- apr_bucket_brigade *b;
-} core_ctx_t;
-
static int core_input_filter(ap_filter_t *f, apr_bucket_brigade *b, ap_input_mode_t mode, apr_off_t *readbytes)
{
apr_bucket *e;
apr_status_t rv;
- core_ctx_t *ctx = f->ctx;
+ core_net_rec *net = f->ctx;
+ core_ctx_t *ctx = net->in_ctx;
const char *str;
apr_size_t len;
+ int keptalive = f->c->keepalive == 1;
if (!ctx)
{
- f->ctx = ctx = apr_pcalloc(f->c->pool, sizeof(*ctx));
+ ctx = apr_pcalloc(f->c->pool, sizeof(*ctx));
ctx->b = apr_brigade_create(f->c->pool);
/* seed the brigade with the client socket. */
- e = apr_bucket_socket_create(f->c->client_socket);
+ e = apr_bucket_socket_create(net->client_socket);
APR_BRIGADE_INSERT_TAIL(ctx->b, e);
+ net->in_ctx = ctx;
+ ctx->first_line = 1;
+ }
+
+ if (ctx->first_line) {
+ apr_setsocketopt(net->client_socket, APR_SO_TIMEOUT,
+ (int)(keptalive
+ ? f->c->base_server->keep_alive_timeout * APR_USEC_PER_SEC
+ : f->c->base_server->timeout * APR_USEC_PER_SEC));
+ ctx->first_line = 0;
+ }
+ else {
+ if (keptalive) {
+ apr_setsocketopt(net->client_socket, APR_SO_TIMEOUT,
+ (int)(f->c->base_server->timeout * APR_USEC_PER_SEC));
+ }
}
/* ### This is bad. */
* is to send the headers if they haven't already been sent, and then send
* the actual data.
*/
-typedef struct CORE_OUTPUT_FILTER_CTX {
- apr_bucket_brigade *b;
- apr_pool_t *subpool; /* subpool of c->pool used for data saved after a
- * request is finished
- */
- int subpool_has_stuff; /* anything in the subpool? */
-} core_output_filter_ctx_t;
-
#define MAX_IOVEC_TO_WRITE 16
static apr_status_t core_output_filter(ap_filter_t *f, apr_bucket_brigade *b)
{
apr_status_t rv;
conn_rec *c = f->c;
- core_output_filter_ctx_t *ctx = f->ctx;
+ core_net_rec *net = f->ctx;
+ core_output_filter_ctx_t *ctx = net->out_ctx;
if (ctx == NULL) {
- f->ctx = ctx = apr_pcalloc(c->pool, sizeof(core_output_filter_ctx_t));
+ ctx = apr_pcalloc(c->pool, sizeof(core_output_filter_ctx_t));
+ net->out_ctx = ctx;
}
/* If we have a saved brigade, concatenate the new brigade to it */
/* Prepare the socket to be reused */
flags |= APR_SENDFILE_DISCONNECT_SOCKET;
}
- rv = sendfile_it_all(c, /* the connection */
+ rv = sendfile_it_all(net, /* the network information */
fd, /* the file to send */
&hdtr, /* header and trailer iovecs */
foffset, /* offset in the file to begin
#endif
{
apr_size_t unused_bytes_sent;
- rv = emulate_sendfile(c, fd, &hdtr, foffset, flen,
+ rv = emulate_sendfile(net, fd, &hdtr, foffset, flen,
&unused_bytes_sent);
}
fd = NULL;
else {
apr_size_t unused_bytes_sent;
- rv = writev_it_all(c->client_socket,
+ rv = writev_it_all(net->client_socket,
vec, nvec,
nbytes, &unused_bytes_sent);
}
return core_create_req(pr);
}
+static conn_rec *core_create_conn(apr_pool_t *ptrans, apr_socket_t *csd,
+ int my_child_num)
+{
+ core_net_rec *net = apr_palloc(ptrans, sizeof(*net));
+
+ net->in_ctx = NULL;
+ net->out_ctx = NULL;
+ net->c = ap_core_new_connection(ptrans, ap_server_conf, csd,
+ net, my_child_num);
+
+ ap_add_input_filter("CORE_IN", net, NULL, net->c);
+ ap_add_output_filter("CORE", net, NULL, net->c);
+ return net->c;
+}
+
static void register_hooks(apr_pool_t *p)
{
ap_hook_post_config(core_post_config,NULL,NULL,APR_HOOK_REALLY_FIRST);
ap_hook_type_checker(do_nothing,NULL,NULL,APR_HOOK_REALLY_LAST);
ap_hook_fixups(core_override_type,NULL,NULL,APR_HOOK_REALLY_FIRST);
ap_hook_access_checker(do_nothing,NULL,NULL,APR_HOOK_REALLY_LAST);
+ ap_hook_create_connection(core_create_conn, NULL, NULL, APR_HOOK_REALLY_LAST);
ap_hook_create_request(core_create_req, NULL, NULL, APR_HOOK_MIDDLE);
APR_OPTIONAL_HOOK(proxy, create_req, core_create_proxy_req, NULL, NULL,
APR_HOOK_MIDDLE);
return;
}
- current_conn = ap_new_connection(p, ap_server_conf, sock, conn_id);
+ current_conn = ap_run_create_connection(p, sock, conn_id);
if (current_conn) {
ap_process_connection(current_conn);
ap_sock_disable_nagle(sock);
}
- current_conn = ap_new_connection(p, ap_server_conf, sock, conn_id);
+ current_conn = ap_run_create_connection(p, ap_server_conf, sock, conn_id);
if (current_conn) {
ap_process_connection(current_conn);
}
rc == 0 && rd.ulData != WORKTYPE_EXIT) {
pconn = worker_args->pconn;
ap_sock_disable_nagle(worker_args->conn_sd);
- current_conn = ap_new_connection(pconn, ap_server_conf, worker_args->conn_sd, conn_id);
+ current_conn = ap_run_create_connection(pconn, worker_args->conn_sd, conn_id);
if (current_conn) {
ap_process_connection(current_conn);
*/
ap_sock_disable_nagle(csd);
- current_conn = ap_new_connection(ptrans, ap_server_conf, csd, my_worker_num);
+ current_conn = ap_run_create_connection(ptrans, csd, my_worker_num);
if (current_conn) {
ap_process_connection(current_conn);
}
ap_sock_disable_nagle(sock);
}
- current_conn = ap_new_connection(p, ap_server_conf, sock, conn_id);
+ current_conn = ap_run_create_connection(p, ap_server_conf, sock, conn_id);
if (current_conn) {
ap_process_connection(current_conn);
}
ap_sock_disable_nagle(csd);
- current_conn = ap_new_connection(ptrans, ap_server_conf, csd,
- my_child_num);
+ current_conn = ap_run_create_connection(ptrans, csd, my_child_num);
if (current_conn) {
ap_process_connection(current_conn);
}
ap_sock_disable_nagle(csd);
- current_conn = ap_new_connection(ptrans, ap_server_conf, csd,
+ current_conn = ap_run_create_connection(ptrans, csd,
THREAD_GLOBAL(thread_num));
if (current_conn) {
ap_sock_disable_nagle(sock);
- current_conn = ap_new_connection(p, ap_server_conf, sock, conn_id);
+ current_conn = ap_run_create_connection(p, sock, conn_id);
if (current_conn) {
ap_process_connection(current_conn);
}
/* ### is this correct? Shouldn't be inheritable (at this point) */
apr_os_sock_make(&context->sock, &sockinfo, context->ptrans);
- c = ap_new_connection(context->ptrans, ap_server_conf, context->sock,
+ c = ap_run_create_connection(context->ptrans, context->sock,
thread_num);
if (c) {
ap_sock_disable_nagle(sock);
- current_conn = ap_new_connection(p, ap_server_conf, sock, conn_id);
+ current_conn = ap_run_create_connection(p, sock, conn_id);
if (current_conn) {
ap_process_connection(current_conn);
}
request_rec *r;
apr_pool_t *p;
const char *expect;
- int access_status, keptalive;
+ int access_status;
apr_pool_create(&p, conn->pool);
r = apr_pcalloc(p, sizeof(request_rec));
r->connection = conn;
r->server = conn->base_server;
- keptalive = conn->keepalive == 1;
conn->keepalive = 0;
r->user = NULL;
r->status = HTTP_REQUEST_TIME_OUT; /* Until we get a request */
r->the_request = NULL;
- apr_setsocketopt(conn->client_socket, APR_SO_TIMEOUT,
- (int)(keptalive
- ? r->server->keep_alive_timeout * APR_USEC_PER_SEC
- : r->server->timeout * APR_USEC_PER_SEC));
-
/* Get the request... */
if (!read_request_line(r)) {
if (r->status == HTTP_REQUEST_URI_TOO_LARGE) {
}
return NULL;
}
- if (keptalive) {
- apr_setsocketopt(r->connection->client_socket, APR_SO_TIMEOUT,
- (int)(r->server->timeout * APR_USEC_PER_SEC));
- }
+
if (!r->assbackwards) {
get_mime_headers(r);
if (r->status != HTTP_REQUEST_TIME_OUT) {
const apr_table_entry_t *hdrs = (const apr_table_entry_t *) hdrs_arr->elts;
int i;
apr_port_t rport;
- apr_sockaddr_t *remotesa;
/* use a temporary apr_table_t which we'll overlap onto
* r->subprocess_env later
apr_table_addn(e, "SERVER_ADMIN", s->server_admin); /* Apache */
apr_table_addn(e, "SCRIPT_FILENAME", r->filename); /* Apache */
- apr_socket_addr_get(&remotesa, APR_REMOTE, c->client_socket);
- apr_sockaddr_port_get(&rport, remotesa);
+ apr_sockaddr_port_get(&rport, c->remote_addr);
apr_table_addn(e, "REMOTE_PORT", apr_psprintf(r->pool, "%d", rport));
if (r->user) {
server_rec *s;
server_rec *last_s;
name_chain *src;
- apr_sockaddr_t *localsa;
last_s = NULL;
- apr_socket_addr_get(&localsa, APR_LOCAL, r->connection->client_socket);
- apr_sockaddr_port_get(&port, localsa);
+
+ apr_sockaddr_port_get(&port, r->connection->local_addr);
/* Recall that the name_chain is a list of server_addr_recs, some of
* whose ports may not match. Also each server may appear more than
server_rec *last_s;
name_chain *src;
apr_port_t port;
- apr_sockaddr_t *localsa;
- apr_socket_addr_get(&localsa, APR_LOCAL, r->connection->client_socket);
- apr_sockaddr_port_get(&port, localsa);
-
+ apr_sockaddr_port_get(&port, r->connection->local_addr);
+
/*
* This is in conjunction with the ServerPath code in http_core, so we
* get the right host attached to a non- Host-sending request.
/* scan the hash apr_table_t for an exact match first */
trav = find_ipaddr(conn->local_addr);
+
if (trav) {
/* save the name_chain for later in case this is a name-vhost */
conn->vhost_lookup_data = trav->names;
* matching this port
*/
apr_sockaddr_port_get(&port, conn->local_addr);
+
trav = find_default_server(port);
if (trav) {
conn->vhost_lookup_data = trav->names;