]> granicus.if.org Git - apache/blob - modules/http2/h2_mplx.h
Backport
[apache] / modules / http2 / h2_mplx.h
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 #ifndef __mod_h2__h2_mplx__
17 #define __mod_h2__h2_mplx__
18
19 /**
20  * The stream multiplexer. It pushes buckets from the connection
21  * thread to the stream threads and vice versa. It's thread-safe
22  * to use.
23  *
24  * There is one h2_mplx instance for each h2_session, which sits on top
25  * of a particular httpd conn_rec. Input goes from the connection to
26  * the stream tasks. Output goes from the stream tasks to the connection,
27  * e.g. the client.
28  *
29  * For each stream, there can be at most "H2StreamMaxMemSize" output bytes
30  * queued in the multiplexer. If a task thread tries to write more
31  * data, it is blocked until space becomes available.
32  *
33  * Writing input is never blocked. In order to use flow control on the input,
34  * the mplx can be polled for input data consumption.
35  */
36
37 struct apr_pool_t;
38 struct apr_thread_mutex_t;
39 struct apr_thread_cond_t;
40 struct h2_bucket_beam;
41 struct h2_config;
42 struct h2_ihash_t;
43 struct h2_response;
44 struct h2_task;
45 struct h2_stream;
46 struct h2_request;
47 struct apr_thread_cond_t;
48 struct h2_workers;
49 struct h2_iqueue;
50 struct h2_ngn_shed;
51 struct h2_req_engine;
52
53 #include <apr_queue.h>
54
55 typedef struct h2_mplx h2_mplx;
56
57 /**
58  * Callback invoked for every stream that had input data read since
59  * the last invocation.
60  */
61 typedef void h2_mplx_consumed_cb(void *ctx, int stream_id, apr_off_t consumed);
62
63 struct h2_mplx {
64     long id;
65     conn_rec *c;
66     apr_pool_t *pool;
67     apr_bucket_alloc_t *bucket_alloc;
68
69     APR_RING_ENTRY(h2_mplx) link;
70
71     unsigned int aborted : 1;
72     unsigned int need_registration : 1;
73
74     struct h2_ihash_t *streams;     /* all streams currently processing */
75     struct h2_ihash_t *shold;       /* all streams done with task ongoing */
76     struct h2_ihash_t *spurge;      /* all streams done, ready for destroy */
77
78     struct h2_iqueue *q;            /* all stream ids that need to be started */
79     struct h2_ihash_t *sready;      /* all streams ready for response */
80     struct h2_ihash_t *sresume;     /* all streams that can be resumed */
81     
82     struct h2_ihash_t *tasks;       /* all tasks started and not destroyed */
83     struct h2_ihash_t *redo_tasks;  /* all tasks that need to be redone */
84     
85     apr_uint32_t max_streams;        /* max # of concurrent streams */
86     apr_uint32_t max_stream_started; /* highest stream id that started processing */
87     apr_uint32_t workers_busy;       /* # of workers processing on this mplx */
88     apr_uint32_t workers_limit;      /* current # of workers limit, dynamic */
89     apr_uint32_t workers_def_limit;  /* default # of workers limit */
90     apr_uint32_t workers_max;        /* max, hard limit # of workers in a process */
91     apr_time_t last_idle_block;      /* last time, this mplx entered IDLE while
92                                       * streams were ready */
93     apr_time_t last_limit_change;    /* last time, worker limit changed */
94     apr_interval_time_t limit_change_interval;
95
96     apr_thread_mutex_t *lock;
97     struct apr_thread_cond_t *added_output;
98     struct apr_thread_cond_t *task_thawed;
99     struct apr_thread_cond_t *join_wait;
100     
101     apr_size_t stream_max_mem;
102     apr_interval_time_t stream_timeout;
103     
104     apr_pool_t *spare_io_pool;
105     apr_array_header_t *spare_slaves; /* spare slave connections */
106     
107     struct h2_workers *workers;
108     int tx_handles_reserved;
109     apr_size_t tx_chunk_size;
110     
111     h2_mplx_consumed_cb *input_consumed;
112     void *input_consumed_ctx;
113
114     struct h2_ngn_shed *ngn_shed;
115 };
116
117
118
119 /*******************************************************************************
120  * Object lifecycle and information.
121  ******************************************************************************/
122
123 apr_status_t h2_mplx_child_init(apr_pool_t *pool, server_rec *s);
124
125 /**
126  * Create the multiplexer for the given HTTP2 session. 
127  * Implicitly has reference count 1.
128  */
129 h2_mplx *h2_mplx_create(conn_rec *c, apr_pool_t *master, 
130                         const struct h2_config *conf, 
131                         apr_interval_time_t stream_timeout,
132                         struct h2_workers *workers);
133
134 /**
135  * Decreases the reference counter of this mplx and waits for it
136  * to reached 0, destroy the mplx afterwards.
137  * This is to be called from the thread that created the mplx in
138  * the first place.
139  * @param m the mplx to be released and destroyed
140  * @param wait condition var to wait on for ref counter == 0
141  */ 
142 apr_status_t h2_mplx_release_and_join(h2_mplx *m, struct apr_thread_cond_t *wait);
143
144 /**
145  * Aborts the multiplexer. It will answer all future invocation with
146  * APR_ECONNABORTED, leading to early termination of ongoing streams.
147  */
148 void h2_mplx_abort(h2_mplx *mplx);
149
150 struct h2_task *h2_mplx_pop_task(h2_mplx *mplx, int *has_more);
151
152 void h2_mplx_task_done(h2_mplx *m, struct h2_task *task, struct h2_task **ptask);
153
154 /**
155  * Shut down the multiplexer gracefully. Will no longer schedule new streams
156  * but let the ongoing ones finish normally.
157  * @return the highest stream id being/been processed
158  */
159 apr_uint32_t h2_mplx_shutdown(h2_mplx *m);
160
161 /*******************************************************************************
162  * IO lifetime of streams.
163  ******************************************************************************/
164
165 /**
166  * Notifies mplx that a stream has finished processing.
167  * 
168  * @param m the mplx itself
169  * @param stream the id of the stream being done
170  * @param rst_error if != 0, the stream was reset with the error given
171  *
172  */
173 apr_status_t h2_mplx_stream_done(h2_mplx *m, struct h2_stream *stream);
174
175 /**
176  * Waits on output data from any stream in this session to become available. 
177  * Returns APR_TIMEUP if no data arrived in the given time.
178  */
179 apr_status_t h2_mplx_out_trywait(h2_mplx *m, apr_interval_time_t timeout,
180                                  struct apr_thread_cond_t *iowait);
181
182 /*******************************************************************************
183  * Stream processing.
184  ******************************************************************************/
185
186 /**
187  * Process a stream request.
188  * 
189  * @param m the multiplexer
190  * @param stream the identifier of the stream
191  * @param r the request to be processed
192  * @param cmp the stream priority compare function
193  * @param ctx context data for the compare function
194  */
195 apr_status_t h2_mplx_process(h2_mplx *m, struct h2_stream *stream, 
196                              h2_stream_pri_cmp *cmp, void *ctx);
197
198 /**
199  * Stream priorities have changed, reschedule pending requests.
200  * 
201  * @param m the multiplexer
202  * @param cmp the stream priority compare function
203  * @param ctx context data for the compare function
204  */
205 apr_status_t h2_mplx_reprioritize(h2_mplx *m, h2_stream_pri_cmp *cmp, void *ctx);
206
207 /**
208  * Register a callback for the amount of input data consumed per stream. The
209  * will only ever be invoked from the thread creating this h2_mplx, e.g. when
210  * calls from that thread into this h2_mplx are made.
211  *
212  * @param m the multiplexer to register the callback at
213  * @param cb the function to invoke
214  * @param ctx user supplied argument to invocation.
215  */
216 void h2_mplx_set_consumed_cb(h2_mplx *m, h2_mplx_consumed_cb *cb, void *ctx);
217
218
219 typedef apr_status_t stream_ev_callback(void *ctx, int stream_id);
220
221 /**
222  * Dispatch events for the master connection, such as
223  * - resume: new output data has arrived for a suspended stream
224  * - response: the response for a stream is ready
225  */
226 apr_status_t h2_mplx_dispatch_master_events(h2_mplx *m, 
227                                             stream_ev_callback *on_resume, 
228                                             stream_ev_callback *on_response, 
229                                             void *ctx);
230
231 apr_status_t h2_mplx_suspend_stream(h2_mplx *m, int stream_id);
232
233 /*******************************************************************************
234  * Output handling of streams.
235  ******************************************************************************/
236
237 /**
238  * Opens the output for the given stream with the specified response.
239  */
240 apr_status_t h2_mplx_out_open(h2_mplx *mplx, int stream_id,
241                               struct h2_response *response);
242
243 /*******************************************************************************
244  * h2_mplx list Manipulation.
245  ******************************************************************************/
246
247 /**
248  * The magic pointer value that indicates the head of a h2_mplx list
249  * @param  b The mplx list
250  * @return The magic pointer value
251  */
252 #define H2_MPLX_LIST_SENTINEL(b)        APR_RING_SENTINEL((b), h2_mplx, link)
253
254 /**
255  * Determine if the mplx list is empty
256  * @param b The list to check
257  * @return true or false
258  */
259 #define H2_MPLX_LIST_EMPTY(b)   APR_RING_EMPTY((b), h2_mplx, link)
260
261 /**
262  * Return the first mplx in a list
263  * @param b The list to query
264  * @return The first mplx in the list
265  */
266 #define H2_MPLX_LIST_FIRST(b)   APR_RING_FIRST(b)
267
268 /**
269  * Return the last mplx in a list
270  * @param b The list to query
271  * @return The last mplx int he list
272  */
273 #define H2_MPLX_LIST_LAST(b)    APR_RING_LAST(b)
274
275 /**
276  * Insert a single mplx at the front of a list
277  * @param b The list to add to
278  * @param e The mplx to insert
279  */
280 #define H2_MPLX_LIST_INSERT_HEAD(b, e) do {                             \
281 h2_mplx *ap__b = (e);                                        \
282 APR_RING_INSERT_HEAD((b), ap__b, h2_mplx, link);        \
283 } while (0)
284
285 /**
286  * Insert a single mplx at the end of a list
287  * @param b The list to add to
288  * @param e The mplx to insert
289  */
290 #define H2_MPLX_LIST_INSERT_TAIL(b, e) do {                             \
291 h2_mplx *ap__b = (e);                                   \
292 APR_RING_INSERT_TAIL((b), ap__b, h2_mplx, link);        \
293 } while (0)
294
295 /**
296  * Get the next mplx in the list
297  * @param e The current mplx
298  * @return The next mplx
299  */
300 #define H2_MPLX_NEXT(e) APR_RING_NEXT((e), link)
301 /**
302  * Get the previous mplx in the list
303  * @param e The current mplx
304  * @return The previous mplx
305  */
306 #define H2_MPLX_PREV(e) APR_RING_PREV((e), link)
307
308 /**
309  * Remove a mplx from its list
310  * @param e The mplx to remove
311  */
312 #define H2_MPLX_REMOVE(e)       APR_RING_REMOVE((e), link)
313
314 /*******************************************************************************
315  * h2_mplx DoS protection
316  ******************************************************************************/
317
318 /**
319  * Master connection has entered idle mode.
320  * @param m the mplx instance of the master connection
321  * @return != SUCCESS iff connection should be terminated
322  */
323 apr_status_t h2_mplx_idle(h2_mplx *m);
324
325 /*******************************************************************************
326  * h2_req_engine handling
327  ******************************************************************************/
328
329 typedef void h2_output_consumed(void *ctx, conn_rec *c, apr_off_t consumed);
330 typedef apr_status_t h2_mplx_req_engine_init(struct h2_req_engine *engine, 
331                                              const char *id, 
332                                              const char *type,
333                                              apr_pool_t *pool, 
334                                              apr_uint32_t req_buffer_size,
335                                              request_rec *r,
336                                              h2_output_consumed **pconsumed,
337                                              void **pbaton);
338
339 apr_status_t h2_mplx_req_engine_push(const char *ngn_type, 
340                                      request_rec *r, 
341                                      h2_mplx_req_engine_init *einit);
342 apr_status_t h2_mplx_req_engine_pull(struct h2_req_engine *ngn, 
343                                      apr_read_type_e block, 
344                                      apr_uint32_t capacity, 
345                                      request_rec **pr);
346 void h2_mplx_req_engine_done(struct h2_req_engine *ngn, conn_rec *r_conn);
347
348 #endif /* defined(__mod_h2__h2_mplx__) */