]> granicus.if.org Git - apache/blob - server/listen.c
CGIs work again on UNIX because ap_create_process() works again on UNIX.
[apache] / server / listen.c
1 /* ====================================================================
2  * The Apache Software License, Version 1.1
3  *
4  * Copyright (c) 2000 The Apache Software Foundation.  All rights
5  * reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  *
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in
16  *    the documentation and/or other materials provided with the
17  *    distribution.
18  *
19  * 3. The end-user documentation included with the redistribution,
20  *    if any, must include the following acknowledgment:
21  *       "This product includes software developed by the
22  *        Apache Software Foundation (http://www.apache.org/)."
23  *    Alternately, this acknowledgment may appear in the software itself,
24  *    if and wherever such third-party acknowledgments normally appear.
25  *
26  * 4. The names "Apache" and "Apache Software Foundation" must
27  *    not be used to endorse or promote products derived from this
28  *    software without prior written permission. For written
29  *    permission, please contact apache@apache.org.
30  *
31  * 5. Products derived from this software may not be called "Apache",
32  *    nor may "Apache" appear in their name, without prior written
33  *    permission of the Apache Software Foundation.
34  *
35  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
39  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46  * SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Apache Software Foundation.  For more
51  * information on the Apache Software Foundation, please see
52  * <http://www.apache.org/>.
53  *
54  * Portions of this software are based upon public domain software
55  * originally written at the National Center for Supercomputing Applications,
56  * University of Illinois, Urbana-Champaign.
57  */
58
59 #include "apr_network_io.h"
60
61 #define CORE_PRIVATE
62 #include "ap_config.h"
63 #include "httpd.h"
64 #include "http_config.h"
65 #include "ap_listen.h"
66 #include "http_log.h"
67 #include <string.h>
68
69 ap_listen_rec *ap_listeners;
70 static ap_listen_rec *old_listeners;
71 static int ap_listenbacklog;
72 static int send_buffer_size;
73
74 /* TODO: make_sock is just begging and screaming for APR abstraction */
75 static ap_status_t make_sock(ap_context_t *p, ap_listen_rec *server)
76 {
77     ap_socket_t *s = server->sd;
78     int one = 1;
79     char addr[512];
80     ap_status_t stat;
81     ap_uint32_t port;
82     char *ipaddr;
83
84     ap_get_local_port(&port,s);
85     ap_get_local_ipaddr(&ipaddr,s);
86     ap_snprintf(addr, sizeof(addr), "address %s port %u", ipaddr,
87                 (unsigned) port);
88
89     stat = ap_setsocketopt(s, APR_SO_REUSEADDR, one);
90     if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) {
91         ap_log_error(APLOG_MARK, APLOG_CRIT, stat, NULL,
92                     "make_sock: for %s, setsockopt: (SO_REUSEADDR)", addr);
93         ap_close_socket(s);
94         return stat;
95     }
96     
97     stat = ap_setsocketopt(s, APR_SO_KEEPALIVE, one);
98     if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) {
99         ap_log_error(APLOG_MARK, APLOG_CRIT, stat, NULL,
100                     "make_sock: for %s, setsockopt: (SO_KEEPALIVE)", addr);
101         ap_close_socket(s);
102         return stat;
103     }
104
105     /*
106      * To send data over high bandwidth-delay connections at full
107      * speed we must force the TCP window to open wide enough to keep the
108      * pipe full.  The default window size on many systems
109      * is only 4kB.  Cross-country WAN connections of 100ms
110      * at 1Mb/s are not impossible for well connected sites.
111      * If we assume 100ms cross-country latency,
112      * a 4kB buffer limits throughput to 40kB/s.
113      *
114      * To avoid this problem I've added the SendBufferSize directive
115      * to allow the web master to configure send buffer size.
116      *
117      * The trade-off of larger buffers is that more kernel memory
118      * is consumed.  YMMV, know your customers and your network!
119      *
120      * -John Heidemann <johnh@isi.edu> 25-Oct-96
121      *
122      * If no size is specified, use the kernel default.
123      */
124     if (send_buffer_size) {
125         stat = ap_setsocketopt(s, APR_SO_SNDBUF,  send_buffer_size);
126         if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) {
127             ap_log_error(APLOG_MARK, APLOG_WARNING, stat, NULL,
128                         "make_sock: failed to set SendBufferSize for %s, "
129                         "using default", addr);
130             /* not a fatal error */
131         }
132     }
133
134     if ((stat = ap_bind(s)) != APR_SUCCESS) {
135         ap_log_error(APLOG_MARK, APLOG_CRIT, stat, NULL,
136             "make_sock: could not bind to %s", addr);
137         ap_close_socket(s);
138         return stat;
139     }
140
141     if ((stat = ap_listen(s, ap_listenbacklog)) != APR_SUCCESS) {
142         ap_log_error(APLOG_MARK, APLOG_ERR, stat, NULL,
143             "make_sock: unable to listen for connections on %s", addr);
144         ap_close_socket(s);
145         return stat;
146     }
147
148     server->sd = s;
149     server->active = 1;
150     return APR_SUCCESS;
151 }
152
153
154 static ap_status_t close_listeners_on_exec(void *v)
155 {
156     ap_listen_rec *lr;
157
158     for (lr = ap_listeners; lr; lr = lr->next) {
159         ap_close_socket(lr->sd);
160         lr->active = 0;
161     }
162     return APR_SUCCESS;
163 }
164
165
166 static void alloc_listener(process_rec *process, char *addr, unsigned int port)
167 {
168     ap_listen_rec **walk;
169     ap_listen_rec *new;
170     ap_status_t status;
171     char *oldaddr;
172     unsigned int oldport;
173
174     /* see if we've got an old listener for this address:port */
175     for (walk = &old_listeners; *walk; walk = &(*walk)->next) {
176         ap_get_local_port(&oldport, (*walk)->sd);
177         ap_get_local_ipaddr(&oldaddr,(*walk)->sd);
178         if (!strcmp(oldaddr, addr) && port == oldport) {
179             /* re-use existing record */
180             new = *walk;
181             *walk = new->next;
182             new->next = ap_listeners;
183             ap_listeners = new;
184             return;
185         }
186     }
187
188     /* this has to survive restarts */
189     new = ap_palloc(process->pool, sizeof(ap_listen_rec));
190     new->active = 0;
191     if ((status = ap_create_tcp_socket(&new->sd, process->pool)) != APR_SUCCESS) {
192         ap_log_error(APLOG_MARK, APLOG_CRIT, status, NULL,
193                  "make_sock: failed to get a socket for %s", addr);
194         return;
195     }
196     ap_set_local_port(new->sd, port);
197     ap_set_local_ipaddr(new->sd, addr);
198     new->next = ap_listeners;
199     ap_listeners = new;
200 }
201
202
203 int ap_listen_open(process_rec *process, unsigned port)
204 {
205     ap_context_t *pconf = process->pconf;
206     ap_listen_rec *lr;
207     ap_listen_rec *next;
208     int num_open;
209
210     /* allocate a default listener if necessary */
211     if (ap_listeners == NULL) {
212         alloc_listener(process, APR_ANYADDR, port ? port : DEFAULT_HTTP_PORT);
213     }
214
215     num_open = 0;
216     for (lr = ap_listeners; lr; lr = lr->next) {
217         if (lr->active) {
218             ++num_open;
219         }
220         else {
221             if (make_sock(pconf, lr) == APR_SUCCESS) {
222                 ++num_open;
223                 lr->active = 1;
224             }
225         }
226     }
227
228     /* close the old listeners */
229     for (lr = old_listeners; lr; lr = next) {
230         ap_close_socket(lr->sd);
231         lr->active = 0;
232         next = lr->next;
233 /*      free(lr);*/
234     }
235     old_listeners = NULL;
236
237     ap_register_cleanup(pconf, NULL, ap_null_cleanup, close_listeners_on_exec);
238
239     return num_open ? 0 : -1;
240 }
241
242
243 void ap_listen_pre_config(void)
244 {
245     old_listeners = ap_listeners;
246     ap_listeners = NULL;
247     ap_listenbacklog = DEFAULT_LISTENBACKLOG;
248 }
249
250
251 const char *ap_set_listener(cmd_parms *cmd, void *dummy, char *ips)
252 {
253     char *ports;
254     unsigned short port;
255
256     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
257     if (err != NULL) {
258         return err;
259     }
260
261     ports = strchr(ips, ':');
262     if (ports != NULL) {
263         if (ports == ips) {
264             return "Missing IP address";
265         }
266         else if (ports[1] == '\0') {
267             return "Address must end in :<port-number>";
268         }
269         *(ports++) = '\0';
270     }
271     else {
272         ports = ips;
273     }
274
275     port = atoi(ports);
276     if (!port) {
277         return "Port must be numeric";
278     }
279
280     if (ports == ips) { /* no address */
281         alloc_listener(cmd->server->process, APR_ANYADDR, port);
282     }
283     else {
284         ips[(ports - ips) - 1] = '\0';
285         alloc_listener(cmd->server->process, ips, port);
286     }
287
288     return NULL;
289 }
290
291 const char *ap_set_listenbacklog(cmd_parms *cmd, void *dummy, char *arg) 
292 {
293     int b;
294
295     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
296     if (err != NULL) {
297         return err;
298     }
299
300     b = atoi(arg);
301     if (b < 1) {
302         return "ListenBacklog must be > 0";
303     }
304     ap_listenbacklog = b;
305     return NULL;
306 }
307
308 const char *ap_set_send_buffer_size(cmd_parms *cmd, void *dummy, char *arg)
309 {
310     int s = atoi(arg);
311     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
312     if (err != NULL) {
313         return err;
314     }
315
316     if (s < 512 && s != 0) {
317         return "SendBufferSize must be >= 512 bytes, or 0 for system default.";
318     }
319     send_buffer_size = s;
320     return NULL;
321 }