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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include "ap_listen.h"
20 #include "simple_types.h"
21 #include "simple_io.h"
22 #include "simple_event.h"
24 #include "http_connection.h"
25 #include "util_filter.h"
26 #include "http_main.h"
27 #include "scoreboard.h"
28 #include "http_vhost.h"
30 APLOG_USE_MODULE(mpm_simple);
32 static void simple_io_timeout_cb(simple_core_t * sc, void *baton)
34 /* Code disabled because it does nothing yet but causes a compiler warning */
36 simple_conn_t *scon = (simple_conn_t *) baton;
37 /* pqXXXXX: handle timeouts. */
38 conn_rec *c = scon->c;
43 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ap_server_conf,
44 "io timeout hit (?)");
47 static apr_status_t simple_io_process(simple_conn_t * scon)
53 if (scon->c->clogging_input_filters && !scon->c->aborted) {
54 /* Since we have an input filter which 'cloggs' the input stream,
55 * like mod_ssl, lets just do the normal read from input filters,
56 * like the Worker MPM does.
58 ap_run_process_connection(scon->c);
59 if (scon->cs.state != CONN_STATE_SUSPENDED) {
60 scon->cs.state = CONN_STATE_LINGER;
69 if (scon->pfd.reqevents != 0) {
70 rv = apr_pollcb_remove(sc->pollcb, &scon->pfd);
72 ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf,
73 "simple_io_process: apr_pollcb_remove failure");
74 /*AP_DEBUG_ASSERT(rv == APR_SUCCESS);*/
76 scon->pfd.reqevents = 0;
79 if (scon->cs.state == CONN_STATE_READ_REQUEST_LINE) {
81 ap_run_process_connection(c);
82 /* state will be updated upon return
83 * fall thru to either wait for readability/timeout or
88 scon->cs.state = CONN_STATE_LINGER;
92 if (scon->cs.state == CONN_STATE_WRITE_COMPLETION) {
93 ap_filter_t *output_filter = c->output_filters;
94 while (output_filter->next != NULL) {
95 output_filter = output_filter->next;
98 rv = output_filter->frec->filter_func.out_func(output_filter,
101 if (rv != APR_SUCCESS) {
102 ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf,
103 "network write failure in core output filter");
104 scon->cs.state = CONN_STATE_LINGER;
106 else if (c->data_in_output_filters) {
107 /* Still in WRITE_COMPLETION_STATE:
108 * Set a write timeout for this connection, and let the
109 * event thread poll for writeability.
112 simple_register_timer(scon->sc,
113 simple_io_timeout_cb,
115 scon->c->base_server !=
116 NULL ? scon->c->base_server->
117 timeout : ap_server_conf->timeout,
120 scon->pfd.reqevents = APR_POLLOUT | APR_POLLHUP | APR_POLLERR;
122 rv = apr_pollcb_add(sc->pollcb, &scon->pfd);
124 if (rv != APR_SUCCESS) {
125 ap_log_error(APLOG_MARK, APLOG_WARNING, rv,
127 "apr_pollcb_add: failed in write completion");
128 AP_DEBUG_ASSERT(rv == APR_SUCCESS);
132 else if (c->keepalive != AP_CONN_KEEPALIVE || c->aborted) {
133 scon->cs.state = CONN_STATE_LINGER;
135 else if (c->data_in_input_filters) {
136 scon->cs.state = CONN_STATE_READ_REQUEST_LINE;
139 scon->cs.state = CONN_STATE_CHECK_REQUEST_LINE_READABLE;
143 if (scon->cs.state == CONN_STATE_LINGER) {
144 ap_lingering_close(c);
145 apr_pool_destroy(scon->pool);
149 if (scon->cs.state == CONN_STATE_CHECK_REQUEST_LINE_READABLE) {
150 simple_register_timer(scon->sc,
151 simple_io_timeout_cb,
153 scon->c->base_server !=
154 NULL ? scon->c->base_server->
155 timeout : ap_server_conf->timeout,
158 scon->pfd.reqevents = APR_POLLIN;
160 rv = apr_pollcb_add(sc->pollcb, &scon->pfd);
163 ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf,
164 "process_socket: apr_pollcb_add failure in read request line");
165 AP_DEBUG_ASSERT(rv == APR_SUCCESS);
172 ap_lingering_close(c);
173 apr_pool_destroy(scon->pool);
177 static void *simple_io_invoke(apr_thread_t * thread, void *baton)
179 simple_sb_t *sb = (simple_sb_t *) baton;
180 simple_conn_t *scon = (simple_conn_t *) sb->baton;
183 scon->c->current_thread = thread;
185 rv = simple_io_process(scon);
188 ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, ap_server_conf,
189 "simple_io_invoke: simple_io_process failed (?)");
195 static void *simple_io_setup_conn(apr_thread_t * thread, void *baton)
201 simple_conn_t *scon = (simple_conn_t *) baton;
203 /* pqXXXXX: remove this. */
204 ap_create_sb_handle(&sbh, scon->pool, 0, 0);
206 scon->ba = apr_bucket_alloc_create(scon->pool);
208 scon->c = ap_run_create_connection(scon->pool, ap_server_conf, scon->sock,
209 conn_id, sbh, scon->ba);
210 /* XXX: handle failure */
212 scon->c->cs = &scon->cs;
213 sb = apr_pcalloc(scon->pool, sizeof(simple_sb_t));
215 scon->c->current_thread = thread;
217 scon->pfd.p = scon->pool;
218 scon->pfd.desc_type = APR_POLL_SOCKET;
219 scon->pfd.desc.s = scon->sock;
220 scon->pfd.reqevents = APR_POLLIN;
222 sb->type = SIMPLE_PT_CORE_IO;
224 scon->pfd.client_data = sb;
226 ap_update_vhost_given_ip(scon->c);
228 rv = ap_run_pre_connection(scon->c, scon->sock);
229 if (rv != OK && rv != DONE) {
230 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
231 "simple_io_setup_conn: connection aborted");
232 scon->c->aborted = 1;
235 scon->cs.state = CONN_STATE_READ_REQUEST_LINE;
237 rv = simple_io_process(scon);
240 ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, ap_server_conf,
241 "simple_io_setup_conn: simple_io_process failed (?)");
247 apr_status_t simple_io_accept(simple_core_t * sc, simple_sb_t * sb)
251 apr_socket_t *socket;
252 ap_listen_rec *lr = (ap_listen_rec *) sb->baton;
254 /* pqXXXXXX: Consider doing pool recycling like the event/worker MPMs do. */
255 apr_pool_create(&ptrans, NULL);
257 apr_pool_tag(ptrans, "transaction");
259 rv = apr_socket_accept(&socket, lr->sd, ptrans);
261 /* pqXXXXXX: unixd.c has _tons_ of custom handling on return values
262 * from accept, but it seems really crazy, it either worked, or didn't,
263 * but taking this approach of swallowing the error it is possible we have a
264 * fatal error on our listening socket, but we don't notice.
266 * Need to discuss this on dev@
268 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL,
269 "simple_io_accept: apr_socket_accept failed");
273 simple_conn_t *scon = apr_pcalloc(ptrans, sizeof(simple_conn_t));
278 return apr_thread_pool_push(sc->workers,
279 simple_io_setup_conn,
281 APR_THREAD_TASK_PRIORITY_NORMAL, NULL);
287 apr_status_t simple_io_event_process(simple_core_t * sc, simple_sb_t * sb)
289 /* pqXXXXX: In theory, if we have non-blocking operations on the connection
290 * we can do them here, before pushing to another thread, thats just
291 * not implemented right now.
293 return apr_thread_pool_push(sc->workers,
295 sb, APR_THREAD_TASK_PRIORITY_NORMAL, NULL);