1 /* Copyright 2015 greenbytes GmbH (https://www.greenbytes.de)
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
21 #include <http_core.h>
22 #include <http_config.h>
24 #include <http_connection.h>
25 #include <http_protocol.h>
26 #include <http_request.h>
28 #include "h2_private.h"
29 #include "h2_config.h"
32 #include "h2_session.h"
33 #include "h2_stream.h"
34 #include "h2_stream_set.h"
36 #include "h2_worker.h"
37 #include "h2_workers.h"
40 static struct h2_workers *workers;
42 static apr_status_t h2_session_process(h2_session *session);
44 static h2_mpm_type_t mpm_type = H2_MPM_UNKNOWN;
45 static module *mpm_module;
46 static module *ssl_module;
49 static void check_modules()
53 for (i = 0; ap_loaded_modules[i]; ++i) {
54 module *m = ap_loaded_modules[i];
55 if (!strcmp("event.c", m->name)) {
56 mpm_type = H2_MPM_EVENT;
59 else if (!strcmp("worker.c", m->name)) {
60 mpm_type = H2_MPM_WORKER;
63 else if (!strcmp("prefork.c", m->name)) {
64 mpm_type = H2_MPM_PREFORK;
67 else if (!strcmp("mod_ssl.c", m->name)) {
75 apr_status_t h2_conn_child_init(apr_pool_t *pool, server_rec *s)
77 h2_config *config = h2_config_sget(s);
78 apr_status_t status = APR_SUCCESS;
79 int minw = h2_config_geti(config, H2_CONF_MIN_WORKERS);
80 int maxw = h2_config_geti(config, H2_CONF_MAX_WORKERS);
82 int max_threads_per_child = 0;
83 int threads_limit = 0;
87 ap_mpm_query(AP_MPMQ_MAX_THREADS, &max_threads_per_child);
88 ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &threads_limit);
91 minw = max_threads_per_child;
100 for (i = 0; ap_loaded_modules[i]; ++i) {
101 module *m = ap_loaded_modules[i];
102 if (!strcmp("event.c", m->name)) {
103 mpm_type = H2_MPM_EVENT;
106 else if (!strcmp("worker.c", m->name)) {
107 mpm_type = H2_MPM_WORKER;
110 else if (!strcmp("prefork.c", m->name)) {
111 mpm_type = H2_MPM_PREFORK;
114 else if (!strcmp("mod_ssl.c", m->name)) {
119 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
120 "h2_workers: min=%d max=%d, mthrpchild=%d, thr_limit=%d",
121 minw, maxw, max_threads_per_child, threads_limit);
123 workers = h2_workers_create(s, pool, minw, maxw);
124 idle_secs = h2_config_geti(config, H2_CONF_MAX_WORKER_IDLE_SECS);
125 h2_workers_set_max_idle_secs(workers, idle_secs);
130 h2_mpm_type_t h2_conn_mpm_type(void) {
135 module *h2_conn_mpm_module(void) {
140 apr_status_t h2_conn_rprocess(request_rec *r)
142 h2_config *config = h2_config_rget(r);
145 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "h2_conn_process start");
147 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02911)
148 "workers not initialized");
152 session = h2_session_rcreate(r, config, workers);
157 return h2_session_process(session);
160 apr_status_t h2_conn_main(conn_rec *c)
162 h2_config *config = h2_config_get(c);
165 ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, "h2_conn_main start");
167 ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(02912)
168 "workers not initialized");
172 session = h2_session_create(c, config, workers);
177 return h2_session_process(session);
180 apr_status_t h2_session_process(h2_session *session)
182 apr_status_t status = APR_SUCCESS;
184 apr_interval_time_t wait_micros = 0;
185 static const int MAX_WAIT_MICROS = 200 * 1000;
187 /* Start talking to the client. Apart from protocol meta data,
188 * we mainly will see new http/2 streams opened by the client, which
189 * basically are http requests we need to dispatch.
191 * There will be bursts of new streams, to be served concurrently,
192 * followed by long pauses of no activity.
194 * Since the purpose of http/2 is to allow siumultaneous streams, we
195 * need to dispatch the handling of each stream into a separate worker
196 * thread, keeping this thread open for sending responses back as
197 * soon as they arrive.
198 * At the same time, we need to continue reading new frames from
199 * our client, which may be meta (WINDOWS_UPDATEs, PING, SETTINGS) or
202 * As long as we have streams open in this session, we cannot really rest
203 * since there are two conditions to wait on: 1. new data from the client,
204 * 2. new data from the open streams to send back.
206 * Only when we have no more streams open, can we do a blocking read
209 * TODO: implement graceful GO_AWAY after configurable idle time
212 ap_update_child_status_from_conn(session->c->sbh, SERVER_BUSY_READ,
215 if (APLOGctrace2(session->c)) {
216 ap_filter_t *filter = session->c->input_filters;
218 ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, session->c,
219 "h2_conn(%ld), has connection filter %s",
220 session->id, filter->frec->name);
221 filter = filter->next;
225 status = h2_session_start(session, &rv);
227 ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, session->c,
228 "h2_session(%ld): starting on %s:%d", session->id,
229 session->c->base_server->defn_name,
230 session->c->local_addr->port);
231 if (status != APR_SUCCESS) {
232 h2_session_abort(session, status, rv);
233 h2_session_destroy(session);
237 while (!h2_session_is_done(session)) {
238 int have_written = 0;
242 status = h2_session_write(session, wait_micros);
243 if (status == APR_SUCCESS) {
247 else if (status == APR_EAGAIN) {
250 else if (status == APR_TIMEUP) {
252 if (wait_micros > MAX_WAIT_MICROS) {
253 wait_micros = MAX_WAIT_MICROS;
257 ap_log_cerror( APLOG_MARK, APLOG_DEBUG, status, session->c,
258 "h2_session(%ld): writing, terminating",
260 h2_session_abort(session, status, 0);
264 /* We would like to do blocking reads as often as possible as they
265 * are more efficient in regard to server resources.
266 * We can do them under the following circumstances:
267 * - we have no open streams and therefore have nothing to write
268 * - we have just started the session and are waiting for the first
269 * two frames to come in. There will always be at least 2 frames as
270 * * h2 will send SETTINGS and SETTINGS-ACK
271 * * h2c will count the header settings as one frame and we
272 * submit our settings and need the ACK.
274 got_streams = !h2_stream_set_is_empty(session->streams);
275 status = h2_session_read(session,
277 || session->frames_received <= 1)?
278 APR_BLOCK_READ : APR_NONBLOCK_READ);
281 /* successful read, reset our idle timers */
289 case APR_ECONNABORTED:
291 ap_log_cerror( APLOG_MARK, APLOG_DEBUG, status, session->c,
292 "h2_session(%ld): reading",
294 h2_session_abort(session, status, 0);
297 ap_log_cerror( APLOG_MARK, APLOG_WARNING, status, session->c,
299 "h2_session(%ld): error reading, terminating",
301 h2_session_abort(session, status, 0);
305 if (!have_read && !have_written
306 && !h2_stream_set_is_empty(session->streams)) {
307 /* Nothing to read or write, we have streams, but
308 * the have no data yet ready to be delivered. Slowly
309 * back off to give others a chance to do their work.
311 if (wait_micros == 0) {
317 ap_log_cerror( APLOG_MARK, APLOG_DEBUG, status, session->c,
318 "h2_session(%ld): done", session->id);
320 ap_update_child_status_from_conn(session->c->sbh, SERVER_CLOSING,
323 h2_session_close(session);
324 h2_session_destroy(session);
330 static void fix_event_conn(conn_rec *c, conn_rec *master);
332 conn_rec *h2_conn_create(conn_rec *master, apr_pool_t *pool)
334 apr_socket_t *socket;
337 AP_DEBUG_ASSERT(master);
339 /* CAVEAT: it seems necessary to setup the conn_rec in the master
340 * connection thread. Other attempts crashed.
341 * HOWEVER: we setup the connection using the pools and other items
342 * from the master connection, since we do not want to allocate
343 * lots of resources here.
344 * Lets allocated pools and everything else when we actually start
345 * working on this new connection.
347 /* Not sure about the scoreboard handle. Reusing the one from the main
348 * connection could make sense, is not really correct, but we cannot
349 * easily create new handles for our worker threads either.
352 socket = ap_get_module_config(master->conn_config, &core_module);
353 c = ap_run_create_connection(pool, master->base_server,
355 master->id^((long)pool),
357 master->bucket_alloc);
359 ap_log_perror(APLOG_MARK, APLOG_ERR, APR_ENOMEM, pool,
360 APLOGNO(02913) "h2_task: creating conn");
363 /* TODO: we simulate that we had already a request on this connection.
364 * This keeps the mod_ssl SNI vs. Host name matcher from answering
366 * when names do not match. We prefer a predictable 421 status.
373 apr_status_t h2_conn_prep(h2_task_env *env, conn_rec *master, h2_worker *worker)
375 h2_config *cfg = h2_config_get(master);
377 ap_log_perror(APLOG_MARK, APLOG_TRACE3, 0, env->pool,
378 "h2_conn(%ld): created from master", master->id);
380 /* Ok, we are just about to start processing the connection and
381 * the worker is calling us to setup all necessary resources.
382 * We can borrow some from the worker itself and some we do as
383 * sub-resources from it, so that we get a nice reuse of
386 env->c.pool = env->pool;
387 env->c.bucket_alloc = h2_worker_get_bucket_alloc(worker);
388 env->c.current_thread = h2_worker_get_thread(worker);
390 env->c.conn_config = ap_create_conn_config(env->pool);
391 env->c.notes = apr_table_make(env->pool, 5);
393 ap_set_module_config(env->c.conn_config, &core_module,
394 h2_worker_get_socket(worker));
397 /* See #19, there is a range of SSL variables to be gotten from
398 * the main connection that should be available in request handlers
400 void *sslcfg = ap_get_module_config(master->conn_config, ssl_module);
402 ap_set_module_config(env->c.conn_config, ssl_module, sslcfg);
406 /* This works for mpm_worker so far. Other mpm modules have
407 * different needs, unfortunately. The most interesting one
410 switch (h2_conn_mpm_type()) {
415 fix_event_conn(&env->c, master);
418 /* fingers crossed */
425 apr_status_t h2_conn_setup(struct h2_task_env *env, struct h2_worker *worker)
427 return h2_conn_prep(env, env->mplx->c, worker);
430 apr_status_t h2_conn_init(struct h2_task_env *env, struct h2_worker *worker)
432 conn_rec *master = env->mplx->c;
433 h2_config *cfg = h2_config_get(master);
435 apr_socket_t *socket = ap_get_module_config(master->conn_config,
437 conn_rec *c = ap_run_create_connection(env->pool, master->base_server,
439 master->id^((long)env->pool),
441 master->bucket_alloc);
443 ap_log_perror(APLOG_MARK, APLOG_ERR, APR_ENOMEM, env->pool,
444 APLOGNO(02914) "h2_task: creating conn");
449 env->c.bucket_alloc = h2_worker_get_bucket_alloc(worker);
450 env->c.current_thread = h2_worker_get_thread(worker);
452 ap_set_module_config(env->c.conn_config, &core_module, socket);
454 /* See #19, there is a range of SSL variables to be gotten from
455 * the main connection that should be available in request handlers
457 void *sslcfg = ap_get_module_config(master->conn_config, ssl_module);
459 ap_set_module_config(env->c.conn_config, ssl_module, sslcfg);
463 /* This works for mpm_worker so far. Other mpm modules have
464 * different needs, unfortunately. The most interesting one
467 switch (h2_conn_mpm_type()) {
472 fix_event_conn(&env->c, master);
475 /* fingers crossed */
482 apr_status_t h2_conn_post(conn_rec *c, h2_worker *worker)
486 /* be sure no one messes with this any more */
487 memset(c, 0, sizeof(*c));
491 apr_status_t h2_conn_process(conn_rec *c, apr_socket_t *socket)
495 c->clogging_input_filters = 1;
496 ap_process_connection(c, socket);
501 /* This is an internal mpm event.c struct which is disguised
502 * as a conn_state_t so that mpm_event can have special connection
503 * state information without changing the struct seen on the outside.
505 * For our task connections we need to create a new beast of this type
506 * and fill it with enough meaningful things that mpm_event reads and
507 * starts processing out task request.
509 typedef struct event_conn_state_t event_conn_state_t;
510 struct event_conn_state_t {
511 /** APR_RING of expiration timeouts */
512 APR_RING_ENTRY(event_conn_state_t) timeout_list;
513 /** the expiration time of the next keepalive timeout */
514 apr_time_t expiration_time;
515 /** connection record this struct refers to */
517 /** request record (if any) this struct refers to */
519 /** is the current conn_rec suspended? (disassociated with
520 * a particular MPM thread; for suspend_/resume_connection
524 /** memory pool to allocate from */
526 /** bucket allocator */
527 apr_bucket_alloc_t *bucket_alloc;
528 /** poll file descriptor information */
530 /** public parts of the connection state */
533 APR_RING_HEAD(timeout_head_t, event_conn_state_t);
535 static void fix_event_conn(conn_rec *c, conn_rec *master)
537 event_conn_state_t *master_cs = ap_get_module_config(master->conn_config,
538 h2_conn_mpm_module());
539 event_conn_state_t *cs = apr_pcalloc(c->pool, sizeof(event_conn_state_t));
540 cs->bucket_alloc = apr_bucket_alloc_create(c->pool);
542 ap_set_module_config(c->conn_config, h2_conn_mpm_module(), cs);
546 cs->p = master_cs->p;
547 cs->pfd = master_cs->pfd;
548 cs->pub = master_cs->pub;
549 cs->pub.state = CONN_STATE_READ_REQUEST_LINE;