]> granicus.if.org Git - apache/blob - server/mpm/simple/simple_io.c
632ff2692e4bfa677e9a33154e88765d49e13970
[apache] / server / mpm / simple / simple_io.c
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "httpd.h"
18 #include "http_log.h"
19 #include "ap_listen.h"
20 #include "simple_types.h"
21 #include "simple_io.h"
22 #include "simple_event.h"
23
24 #include "http_connection.h"
25 #include "util_filter.h"
26 #include "http_main.h"
27 #include "scoreboard.h"
28 #include "http_vhost.h"
29
30 APLOG_USE_MODULE(mpm_simple);
31
32 static void simple_io_timeout_cb(simple_core_t * sc, void *baton)
33 {
34 #if 0
35     simple_conn_t *scon = (simple_conn_t *) baton;
36     /* pqXXXXX: handle timeouts. */
37     conn_rec *c = scon->c;
38     conn_state_t *cs = c->cs;
39
40     cs = NULL;
41 #endif
42
43     ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ap_server_conf,
44                  "io timeout hit (?)");
45 }
46
47 static apr_status_t simple_io_process(simple_conn_t * scon)
48 {
49     apr_status_t rv;
50     simple_core_t *sc;
51     conn_rec *c;
52     conn_state_t *cs;
53
54     if (scon->c->clogging_input_filters && !scon->c->aborted) {
55         /* Since we have an input filter which 'cloggs' the input stream,
56          * like mod_ssl, lets just do the normal read from input filters,
57          * like the Worker MPM does.
58          */
59         ap_run_process_connection(scon->c);
60         if (scon->c->cs->state != CONN_STATE_SUSPENDED) {
61             scon->c->cs->state = CONN_STATE_LINGER;
62         }
63     }
64
65     sc = scon->sc;
66     c = scon->c;
67     cs = c->cs;
68
69     while (!c->aborted) {
70
71         if (cs->pfd.reqevents != 0) {
72             rv = apr_pollcb_remove(sc->pollcb, &cs->pfd);
73             if (rv) {
74                 ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf,
75                              "simple_io_process: apr_pollcb_remove failure");
76                 /*AP_DEBUG_ASSERT(rv == APR_SUCCESS);*/
77             }
78             cs->pfd.reqevents = 0;
79         }
80
81         if (cs->state == CONN_STATE_READ_REQUEST_LINE) {
82             if (!c->aborted) {
83                 ap_run_process_connection(c);
84                 /* state will be updated upon return
85                  * fall thru to either wait for readability/timeout or
86                  * do lingering close
87                  */
88             }
89             else {
90                 cs->state = CONN_STATE_LINGER;
91             }
92         }
93
94         if (cs->state == CONN_STATE_WRITE_COMPLETION) {
95             ap_filter_t *output_filter = c->output_filters;
96             while (output_filter->next != NULL) {
97                 output_filter = output_filter->next;
98             }
99
100             rv = output_filter->frec->filter_func.out_func(output_filter,
101                                                            NULL);
102
103             if (rv != APR_SUCCESS) {
104                 ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf,
105                              "network write failure in core output filter");
106                 cs->state = CONN_STATE_LINGER;
107             }
108             else if (c->data_in_output_filters) {
109                 /* Still in WRITE_COMPLETION_STATE:
110                  * Set a write timeout for this connection, and let the
111                  * event thread poll for writeability.
112                  */
113
114                 simple_register_timer(scon->sc,
115                                       simple_io_timeout_cb,
116                                       scon,
117                                       scon->c->base_server !=
118                                       NULL ? scon->c->base_server->
119                                       timeout : ap_server_conf->timeout,
120                                       scon->pool);
121
122                 cs->pfd.reqevents = APR_POLLOUT | APR_POLLHUP | APR_POLLERR;
123
124                 rv = apr_pollcb_add(sc->pollcb, &cs->pfd);
125
126                 if (rv != APR_SUCCESS) {
127                     ap_log_error(APLOG_MARK, APLOG_WARNING, rv,
128                                  ap_server_conf,
129                                  "apr_pollcb_add: failed in write completion");
130                     AP_DEBUG_ASSERT(rv == APR_SUCCESS);
131                 }
132                 return APR_SUCCESS;
133             }
134             else if (c->keepalive != AP_CONN_KEEPALIVE || c->aborted) {
135                 c->cs->state = CONN_STATE_LINGER;
136             }
137             else if (c->data_in_input_filters) {
138                 cs->state = CONN_STATE_READ_REQUEST_LINE;
139             }
140             else {
141                 cs->state = CONN_STATE_CHECK_REQUEST_LINE_READABLE;
142             }
143         }
144
145         if (cs->state == CONN_STATE_LINGER) {
146             ap_lingering_close(c);
147             apr_pool_destroy(scon->pool);
148             return APR_SUCCESS;
149         }
150
151         if (cs->state == CONN_STATE_CHECK_REQUEST_LINE_READABLE) {
152             simple_register_timer(scon->sc,
153                                   simple_io_timeout_cb,
154                                   scon,
155                                   scon->c->base_server !=
156                                   NULL ? scon->c->base_server->
157                                   timeout : ap_server_conf->timeout,
158                                   scon->pool);
159
160             cs->pfd.reqevents = APR_POLLIN;
161
162             rv = apr_pollcb_add(sc->pollcb, &cs->pfd);
163
164             if (rv) {
165                 ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf,
166                              "process_socket: apr_pollcb_add failure in read request line");
167                 AP_DEBUG_ASSERT(rv == APR_SUCCESS);
168             }
169
170             return APR_SUCCESS;
171         }
172     }
173
174     ap_lingering_close(c);
175     apr_pool_destroy(scon->pool);
176     return APR_SUCCESS;
177 }
178
179 static void *simple_io_invoke(apr_thread_t * thread, void *baton)
180 {
181     simple_sb_t *sb = (simple_sb_t *) baton;
182     simple_conn_t *scon = (simple_conn_t *) sb->baton;
183     apr_status_t rv;
184
185     scon->c->current_thread = thread;
186
187     rv = simple_io_process(scon);
188
189     if (rv) {
190         ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, ap_server_conf,
191                      "simple_io_invoke: simple_io_process failed (?)");
192     }
193
194     return NULL;
195 }
196
197 static void *simple_io_setup_conn(apr_thread_t * thread, void *baton)
198 {
199     apr_status_t rv;
200     ap_sb_handle_t *sbh;
201     conn_state_t *cs;
202     long conn_id = 0;
203     simple_sb_t *sb;
204     simple_conn_t *scon = (simple_conn_t *) baton;
205
206     /* pqXXXXX: remove this. */
207     ap_create_sb_handle(&sbh, scon->pool, 0, 0);
208
209     scon->ba = apr_bucket_alloc_create(scon->pool);
210
211     scon->c = ap_run_create_connection(scon->pool, ap_server_conf, scon->sock,
212                                        conn_id, sbh, scon->ba);
213     /* XXX: handle failure */
214
215     scon->c->cs = apr_pcalloc(scon->pool, sizeof(conn_state_t));
216     cs = scon->c->cs;
217     sb = apr_pcalloc(scon->pool, sizeof(simple_sb_t));
218
219     scon->c->current_thread = thread;
220
221     cs->pfd.p = scon->pool;
222     cs->pfd.desc_type = APR_POLL_SOCKET;
223     cs->pfd.desc.s = scon->sock;
224     cs->pfd.reqevents = APR_POLLIN;
225
226     sb->type = SIMPLE_PT_CORE_IO;
227     sb->baton = scon;
228     cs->pfd.client_data = sb;
229
230     ap_update_vhost_given_ip(scon->c);
231
232     rv = ap_run_pre_connection(scon->c, scon->sock);
233     if (rv != OK && rv != DONE) {
234         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
235                      "simple_io_setup_conn: connection aborted");
236         scon->c->aborted = 1;
237     }
238
239     scon->c->cs->state = CONN_STATE_READ_REQUEST_LINE;
240
241     rv = simple_io_process(scon);
242
243     if (rv) {
244         ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, ap_server_conf,
245                      "simple_io_setup_conn: simple_io_process failed (?)");
246     }
247
248     return NULL;
249 }
250
251 apr_status_t simple_io_accept(simple_core_t * sc, simple_sb_t * sb)
252 {
253     apr_status_t rv;
254     apr_pool_t *ptrans;
255     apr_socket_t *socket;
256     ap_listen_rec *lr = (ap_listen_rec *) sb->baton;
257
258     /* pqXXXXXX: Consider doing pool recycling like the event/worker MPMs do. */
259     apr_pool_create(&ptrans, NULL);
260
261     apr_pool_tag(ptrans, "transaction");
262
263     rv = apr_socket_accept(&socket, lr->sd, ptrans);
264     if (rv) {
265         /* pqXXXXXX: unixd.c has _tons_ of custom handling on return values
266          * from accept, but it seems really crazy, it either worked, or didn't,
267          * but taking this approach of swallowing the error it is possible we have a
268          * fatal error on our listening socket, but we don't notice.
269          *
270          * Need to discuss this on dev@
271          */
272         ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL,
273                      "simple_io_accept: apr_socket_accept failed");
274         return APR_SUCCESS;
275     }
276     else {
277         simple_conn_t *scon = apr_pcalloc(ptrans, sizeof(simple_conn_t));
278         scon->pool = ptrans;
279         scon->sock = socket;
280         scon->sc = sc;
281
282         return apr_thread_pool_push(sc->workers,
283                                     simple_io_setup_conn,
284                                     scon,
285                                     APR_THREAD_TASK_PRIORITY_NORMAL, NULL);
286     }
287
288     return APR_SUCCESS;
289 }
290
291 apr_status_t simple_io_event_process(simple_core_t * sc, simple_sb_t * sb)
292 {
293     /* pqXXXXX: In theory, if we have non-blocking operations on the connection
294      *  we can do them here, before pushing to another thread, thats just
295      * not implemented right now.
296      */
297     return apr_thread_pool_push(sc->workers,
298                                 simple_io_invoke,
299                                 sb, APR_THREAD_TASK_PRIORITY_NORMAL, NULL);
300 }