]> granicus.if.org Git - apache/blob - server/mpm/simple/simple_io.c
Improve ability to compile on C90 Compilers.
[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 "mpm.h"
28 #include "scoreboard.h"
29 #include "http_vhost.h"
30
31 static void
32 simple_io_timeout_cb(simple_core_t *sc,
33                            void *baton)
34 {
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
42   ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ap_server_conf,
43                "io timeout hit (?)");
44 }
45
46 static apr_status_t
47 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     if (cs->state == CONN_STATE_READ_REQUEST_LINE) {
71       if (!c->aborted) {
72         ap_run_process_connection(c);
73         /* state will be updated upon return
74          * fall thru to either wait for readability/timeout or
75          * do lingering close
76          */
77       }
78       else {
79         cs->state = CONN_STATE_LINGER;
80       }
81     }
82
83     if (cs->state == CONN_STATE_WRITE_COMPLETION) {
84       ap_filter_t *output_filter = c->output_filters;
85       while (output_filter->next != NULL) {
86         output_filter = output_filter->next;
87       }
88
89       rv = output_filter->frec->filter_func.out_func(output_filter, NULL);
90       
91       if (rv != APR_SUCCESS) {
92         ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf,
93                      "network write failure in core output filter");
94         cs->state = CONN_STATE_LINGER;
95       }
96       else if (c->data_in_output_filters) {
97         /* Still in WRITE_COMPLETION_STATE:
98          * Set a write timeout for this connection, and let the
99          * event thread poll for writeability.
100          */
101
102         simple_register_timer(scon->sc,
103                               simple_io_timeout_cb,
104                               scon,
105                               scon->c->base_server != NULL ? scon->c->base_server->timeout : ap_server_conf->timeout);
106
107         cs->pfd.reqevents = APR_POLLOUT | APR_POLLHUP | APR_POLLERR;
108
109         rv = apr_pollcb_add(sc->pollcb, &cs->pfd);
110
111         if (rv != APR_SUCCESS) {
112           ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf,
113                        "apr_pollcb_add: failed in write completion");
114           AP_DEBUG_ASSERT(rv == APR_SUCCESS);
115         }
116         return APR_SUCCESS;
117       }
118       else if (c->keepalive != AP_CONN_KEEPALIVE || c->aborted) {
119         c->cs->state = CONN_STATE_LINGER;
120       }
121       else if (c->data_in_input_filters) {
122         cs->state = CONN_STATE_READ_REQUEST_LINE;
123       }
124       else {
125         cs->state = CONN_STATE_CHECK_REQUEST_LINE_READABLE;
126       }
127     }
128
129     if (cs->state == CONN_STATE_LINGER) {
130       ap_lingering_close(c);
131       apr_pool_destroy(scon->pool);
132       return APR_SUCCESS;
133     }
134
135     if (cs->state == CONN_STATE_CHECK_REQUEST_LINE_READABLE) {
136       simple_register_timer(scon->sc,
137                             simple_io_timeout_cb,
138                             scon,
139                             scon->c->base_server != NULL ? scon->c->base_server->timeout : ap_server_conf->timeout);
140
141       cs->pfd.reqevents = APR_POLLIN;
142
143       rv = apr_pollcb_add(sc->pollcb, &cs->pfd);
144
145       if (rv) {
146         ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf,
147                      "process_socket: apr_pollset_add failure in read request line");
148         AP_DEBUG_ASSERT(rv == APR_SUCCESS);
149       }
150
151       return APR_SUCCESS;
152     }
153   }
154
155   ap_lingering_close(c);
156   apr_pool_destroy(scon->pool);
157   return APR_SUCCESS;
158 }
159
160 static void *
161 simple_io_invoke(apr_thread_t* thread, void *baton)
162 {
163   simple_sb_t *sb = (simple_sb_t *)baton;
164   simple_conn_t *scon = (simple_conn_t *)sb->baton;
165   apr_status_t rv;
166   
167   rv = simple_io_process(scon);
168   
169   if (rv) {
170     ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, ap_server_conf,
171                  "simple_io_invoke: simple_io_process failed (?)");
172   }
173
174   return NULL;
175 }
176
177 static void *
178 simple_io_setup_conn(apr_thread_t* thread, void *baton)
179 {
180   apr_status_t rv;
181   ap_sb_handle_t *sbh;
182   conn_state_t *cs;
183   long conn_id = 0;
184   simple_sb_t *sb;
185   simple_conn_t *scon = (simple_conn_t *)baton;
186
187   /* pqXXXXX: remove this. */
188   ap_create_sb_handle(&sbh, scon->pool, 0, 0);
189
190   scon->ba = apr_bucket_alloc_create(scon->pool);
191
192   scon->c = ap_run_create_connection(scon->pool, ap_server_conf, scon->sock,
193                                conn_id, sbh, scon->ba);
194
195   scon->c->cs = apr_pcalloc(scon->pool, sizeof(conn_state_t));
196   cs = scon->c->cs;
197   sb = apr_pcalloc(scon->pool, sizeof(simple_sb_t));
198
199   cs->pfd.p = scon->pool;
200   cs->pfd.desc_type = APR_POLL_SOCKET;
201   cs->pfd.desc.s = scon->sock;
202   cs->pfd.reqevents = APR_POLLIN;
203
204   sb->type = SIMPLE_PT_CORE_IO;
205   sb->baton = scon;
206   cs->pfd.client_data = sb;
207
208   ap_update_vhost_given_ip(scon->c);
209
210   rv = ap_run_pre_connection(scon->c, scon->sock);
211   if (rv != OK && rv != DONE) {
212     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
213                  "simple_io_setup_conn: connection aborted");
214     scon->c->aborted = 1;
215   }
216
217   scon->c->cs->state = CONN_STATE_READ_REQUEST_LINE;
218
219   rv = simple_io_process(scon);
220
221   if (rv) {
222     ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, ap_server_conf,
223                  "simple_io_setup_conn: simple_io_process failed (?)");
224   }
225
226   return NULL;
227 }
228
229 apr_status_t
230 simple_io_accept(simple_core_t *sc, simple_sb_t *sb)
231 {
232   apr_status_t rv;
233   apr_pool_t *ptrans;
234   apr_socket_t *socket;
235   ap_listen_rec *lr = (ap_listen_rec *)sb->baton;
236
237   /* pqXXXXXX: Consider doing pool recycling like the event/worker MPMs do. */
238   apr_pool_create(&ptrans, NULL);
239
240   apr_pool_tag(ptrans, "transaction");
241
242   rv = apr_socket_accept(&socket, lr->sd, ptrans);
243   if (rv) {
244     /* pqXXXXXX: unixd.c has _tons_ of custom handling on return values
245      * from accept, but it seems really crazy, it either worked, or didn't, 
246      * but taking this approach of swallowing the error it is possible we have a 
247      * fatal error on our listening socket, but we don't notice.  
248      * 
249      * Need to discuss this on dev@
250      */
251     ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL,
252                  "simple_io_accept: apr_socket_accept failed");
253     return APR_SUCCESS;
254   }
255   else {
256     simple_conn_t *scon = apr_pcalloc(ptrans, sizeof(simple_conn_t));
257     scon->pool = ptrans;
258     scon->sock = socket;
259     scon->sc = sc;
260
261     return apr_thread_pool_push(sc->workers,
262                                 simple_io_setup_conn,
263                                 scon,
264                                 APR_THREAD_TASK_PRIORITY_NORMAL,
265                                 NULL);
266   }
267
268   return APR_SUCCESS;
269 }
270
271 apr_status_t
272 simple_io_event_process(simple_core_t *sc, simple_sb_t *sb)
273 {
274   /* pqXXXXX: In theory, if we have non-blocking operations on the connection
275    *  we can do them here, before pushing to another thread, thats just
276    * not implemented right now.
277    */
278   return apr_thread_pool_push(sc->workers,
279                               simple_io_invoke,
280                               sb,
281                               APR_THREAD_TASK_PRIORITY_NORMAL,
282                               NULL);
283 }
284