]> granicus.if.org Git - apache/blob - modules/http2/h2_conn.c
On the 2.4.x branch:
[apache] / modules / http2 / h2_conn.c
1 /* Copyright 2015 greenbytes GmbH (https://www.greenbytes.de)
2  *
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
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  
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.
14  */
15
16 #include <assert.h>
17 #include <apr_strings.h>
18
19 #include <ap_mpm.h>
20
21 #include <httpd.h>
22 #include <http_core.h>
23 #include <http_config.h>
24 #include <http_log.h>
25 #include <http_connection.h>
26 #include <http_protocol.h>
27 #include <http_request.h>
28
29 #include <mpm_common.h>
30
31 #include "h2_private.h"
32 #include "h2.h"
33 #include "h2_config.h"
34 #include "h2_ctx.h"
35 #include "h2_filter.h"
36 #include "h2_mplx.h"
37 #include "h2_session.h"
38 #include "h2_stream.h"
39 #include "h2_h2.h"
40 #include "h2_task.h"
41 #include "h2_worker.h"
42 #include "h2_workers.h"
43 #include "h2_conn.h"
44 #include "h2_version.h"
45
46 static struct h2_workers *workers;
47
48 static h2_mpm_type_t mpm_type = H2_MPM_UNKNOWN;
49 static module *mpm_module;
50 static int async_mpm;
51 static apr_socket_t *dummy_socket;
52
53 static void check_modules(int force) 
54 {
55     static int checked = 0;
56     int i;
57
58     if (force || !checked) {
59         for (i = 0; ap_loaded_modules[i]; ++i) {
60             module *m = ap_loaded_modules[i];
61             
62             if (!strcmp("event.c", m->name)) {
63                 mpm_type = H2_MPM_EVENT;
64                 mpm_module = m;
65                 break;
66             }
67             else if (!strcmp("motorz.c", m->name)) {
68                 mpm_type = H2_MPM_MOTORZ;
69                 mpm_module = m;
70                 break;
71             }
72             else if (!strcmp("mpm_netware.c", m->name)) {
73                 mpm_type = H2_MPM_NETWARE;
74                 mpm_module = m;
75                 break;
76             }
77             else if (!strcmp("prefork.c", m->name)) {
78                 mpm_type = H2_MPM_PREFORK;
79                 mpm_module = m;
80                 break;
81             }
82             else if (!strcmp("simple_api.c", m->name)) {
83                 mpm_type = H2_MPM_SIMPLE;
84                 mpm_module = m;
85                 break;
86             }
87             else if (!strcmp("mpm_winnt.c", m->name)) {
88                 mpm_type = H2_MPM_WINNT;
89                 mpm_module = m;
90                 break;
91             }
92             else if (!strcmp("worker.c", m->name)) {
93                 mpm_type = H2_MPM_WORKER;
94                 mpm_module = m;
95                 break;
96             }
97         }
98         checked = 1;
99     }
100 }
101
102 apr_status_t h2_conn_child_init(apr_pool_t *pool, server_rec *s)
103 {
104     const h2_config *config = h2_config_sget(s);
105     apr_status_t status = APR_SUCCESS;
106     int minw, maxw, max_tx_handles, n;
107     int max_threads_per_child = 0;
108     int idle_secs = 0;
109
110     check_modules(1);
111     
112     ap_mpm_query(AP_MPMQ_MAX_THREADS, &max_threads_per_child);
113     
114     status = ap_mpm_query(AP_MPMQ_IS_ASYNC, &async_mpm);
115     if (status != APR_SUCCESS) {
116         /* some MPMs do not implemnent this */
117         async_mpm = 0;
118         status = APR_SUCCESS;
119     }
120
121     h2_config_init(pool);
122     
123     minw = h2_config_geti(config, H2_CONF_MIN_WORKERS);
124     maxw = h2_config_geti(config, H2_CONF_MAX_WORKERS);    
125     if (minw <= 0) {
126         minw = max_threads_per_child;
127     }
128     if (maxw <= 0) {
129         maxw = minw;
130     }
131     
132     /* How many file handles is it safe to use for transfer
133      * to the master connection to be streamed out? 
134      * Is there a portable APR rlimit on NOFILES? Have not
135      * found it. And if, how many of those would we set aside?
136      * This leads all into a process wide handle allocation strategy
137      * which ultimately would limit the number of accepted connections
138      * with the assumption of implicitly reserving n handles for every 
139      * connection and requiring modules with excessive needs to allocate
140      * from a central pool.
141      */
142     n = h2_config_geti(config, H2_CONF_SESSION_FILES);
143     if (n < 0) {
144         max_tx_handles = maxw * 2;
145     }
146     else {
147         max_tx_handles = maxw * n;
148     }
149     
150     ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, s,
151                  "h2_workers: min=%d max=%d, mthrpchild=%d, tx_files=%d", 
152                  minw, maxw, max_threads_per_child, max_tx_handles);
153     workers = h2_workers_create(s, pool, minw, maxw, max_tx_handles);
154     
155     idle_secs = h2_config_geti(config, H2_CONF_MAX_WORKER_IDLE_SECS);
156     h2_workers_set_max_idle_secs(workers, idle_secs);
157  
158     ap_register_input_filter("H2_IN", h2_filter_core_input,
159                              NULL, AP_FTYPE_CONNECTION);
160    
161     status = h2_mplx_child_init(pool, s);
162
163     if (status == APR_SUCCESS) {
164         status = apr_socket_create(&dummy_socket, APR_INET, SOCK_STREAM,
165                                    APR_PROTO_TCP, pool);
166     }
167
168     return status;
169 }
170
171 h2_mpm_type_t h2_conn_mpm_type(void)
172 {
173     check_modules(0);
174     return mpm_type;
175 }
176
177 static module *h2_conn_mpm_module(void)
178 {
179     check_modules(0);
180     return mpm_module;
181 }
182
183 apr_status_t h2_conn_setup(h2_ctx *ctx, conn_rec *c, request_rec *r)
184 {
185     h2_session *session;
186     apr_status_t status;
187     
188     if (!workers) {
189         ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(02911) 
190                       "workers not initialized");
191         return APR_EGENERAL;
192     }
193     
194     if (r) {
195         status = h2_session_rcreate(&session, r, ctx, workers);
196     }
197     else {
198         status = h2_session_create(&session, c, ctx, workers);
199     }
200
201     if (status == APR_SUCCESS) {
202         h2_ctx_session_set(ctx, session);
203     }
204     return status;
205 }
206
207 apr_status_t h2_conn_run(struct h2_ctx *ctx, conn_rec *c)
208 {
209     apr_status_t status;
210     int mpm_state = 0;
211     h2_session *session = h2_ctx_session_get(ctx);
212     
213     ap_assert(session);
214     do {
215         if (c->cs) {
216             c->cs->sense = CONN_SENSE_DEFAULT;
217             c->cs->state = CONN_STATE_HANDLER;
218         }
219     
220         status = h2_session_process(session, async_mpm);
221         
222         if (APR_STATUS_IS_EOF(status)) {
223             ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, c, 
224                           H2_SSSN_LOG(APLOGNO(03045), session, 
225                           "process, closing conn"));
226             c->keepalive = AP_CONN_CLOSE;
227         }
228         else {
229             c->keepalive = AP_CONN_KEEPALIVE;
230         }
231         
232         if (ap_mpm_query(AP_MPMQ_MPM_STATE, &mpm_state)) {
233             break;
234         }
235     } while (!async_mpm
236              && c->keepalive == AP_CONN_KEEPALIVE 
237              && mpm_state != AP_MPMQ_STOPPING);
238     
239     if (c->cs) {
240         switch (session->state) {
241             case H2_SESSION_ST_INIT:
242             case H2_SESSION_ST_CLEANUP:
243             case H2_SESSION_ST_DONE:
244             case H2_SESSION_ST_IDLE:
245                 c->cs->state = CONN_STATE_WRITE_COMPLETION;
246                 break;
247             case H2_SESSION_ST_BUSY:
248             case H2_SESSION_ST_WAIT:
249             default:
250                 c->cs->state = CONN_STATE_HANDLER;
251                 break;
252                 
253         }
254     }
255     
256     return DONE;
257 }
258
259 apr_status_t h2_conn_pre_close(struct h2_ctx *ctx, conn_rec *c)
260 {
261     h2_session *session = h2_ctx_session_get(ctx);
262     if (session) {
263         apr_status_t status = h2_session_pre_close(session, async_mpm);
264         return (status == APR_SUCCESS)? DONE : status;
265     }
266     return DONE;
267 }
268
269 conn_rec *h2_slave_create(conn_rec *master, int slave_id, apr_pool_t *parent)
270 {
271     apr_allocator_t *allocator;
272     apr_status_t status;
273     apr_pool_t *pool;
274     conn_rec *c;
275     void *cfg;
276     module *mpm;
277     
278     ap_assert(master);
279     ap_log_cerror(APLOG_MARK, APLOG_TRACE3, 0, master,
280                   "h2_stream(%ld-%d): create slave", master->id, slave_id);
281     
282     /* We create a pool with its own allocator to be used for
283      * processing a request. This is the only way to have the processing
284      * independant of its parent pool in the sense that it can work in
285      * another thread. Also, the new allocator needs its own mutex to
286      * synchronize sub-pools.
287      */
288     apr_allocator_create(&allocator);
289     apr_allocator_max_free_set(allocator, ap_max_mem_free);
290     status = apr_pool_create_ex(&pool, parent, NULL, allocator);
291     if (status != APR_SUCCESS) {
292         ap_log_cerror(APLOG_MARK, APLOG_ERR, status, master, 
293                       APLOGNO(10004) "h2_session(%ld-%d): create slave pool",
294                       master->id, slave_id);
295         return NULL;
296     }
297     apr_allocator_owner_set(allocator, pool);
298     apr_pool_tag(pool, "h2_slave_conn");
299  
300     c = (conn_rec *) apr_palloc(pool, sizeof(conn_rec));
301     if (c == NULL) {
302         ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_ENOMEM, master, 
303                       APLOGNO(02913) "h2_session(%ld-%d): create slave",
304                       master->id, slave_id);
305         apr_pool_destroy(pool);
306         return NULL;
307     }
308     
309     memcpy(c, master, sizeof(conn_rec));
310         
311     c->master                 = master;
312     c->pool                   = pool;   
313     c->conn_config            = ap_create_conn_config(pool);
314     c->notes                  = apr_table_make(pool, 5);
315     c->input_filters          = NULL;
316     c->output_filters         = NULL;
317     c->bucket_alloc           = apr_bucket_alloc_create(pool);
318     c->data_in_input_filters  = 0;
319     c->data_in_output_filters = 0;
320     c->clogging_input_filters = 1;
321     c->log                    = NULL;
322     c->log_id                 = apr_psprintf(pool, "%ld-%d", 
323                                              master->id, slave_id);
324     /* Simulate that we had already a request on this connection. */
325     c->keepalives             = 1;
326     /* We cannot install the master connection socket on the slaves, as
327      * modules mess with timeouts/blocking of the socket, with
328      * unwanted side effects to the master connection processing.
329      * Fortunately, since we never use the slave socket, we can just install
330      * a single, process-wide dummy and everyone is happy.
331      */
332     ap_set_module_config(c->conn_config, &core_module, dummy_socket);
333     /* TODO: these should be unique to this thread */
334     c->sbh                    = master->sbh;
335     /* TODO: not all mpm modules have learned about slave connections yet.
336      * copy their config from master to slave.
337      */
338     if ((mpm = h2_conn_mpm_module()) != NULL) {
339         cfg = ap_get_module_config(master->conn_config, mpm);
340         ap_set_module_config(c->conn_config, mpm, cfg);
341     }
342
343     ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, 
344                   "h2_stream(%ld-%d): created slave", master->id, slave_id);
345     return c;
346 }
347
348 void h2_slave_destroy(conn_rec *slave)
349 {
350     ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, slave,
351                   "h2_stream(%s): destroy slave", 
352                   apr_table_get(slave->notes, H2_TASK_ID_NOTE));
353     apr_pool_destroy(slave->pool);
354 }
355
356 apr_status_t h2_slave_run_pre_connection(conn_rec *slave, apr_socket_t *csd)
357 {
358     return ap_run_pre_connection(slave, csd);
359 }
360