]> granicus.if.org Git - apache/blob - server/listen.c
Omitted the arg
[apache] / server / listen.c
1 /* ====================================================================
2  * The Apache Software License, Version 1.1
3  *
4  * Copyright (c) 2000-2001 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 #include "apr_strings.h"
61
62 #define APR_WANT_STRFUNC
63 #include "apr_want.h"
64
65 #define CORE_PRIVATE
66 #include "ap_config.h"
67 #include "httpd.h"
68 #include "http_config.h"
69 #include "ap_listen.h"
70 #include "http_log.h"
71 #include "mpm.h"
72 #include "mpm_common.h"
73
74
75 ap_listen_rec *ap_listeners;
76 #if APR_HAVE_IPV6
77 static int default_family = APR_UNSPEC;
78 #else
79 static int default_family = APR_INET;
80 #endif
81 static ap_listen_rec *old_listeners;
82 static int ap_listenbacklog;
83 static int send_buffer_size;
84
85 /* TODO: make_sock is just begging and screaming for APR abstraction */
86 static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server)
87 {
88     apr_socket_t *s = server->sd;
89     int one = 1;
90     apr_status_t stat;
91
92     stat = apr_setsocketopt(s, APR_SO_REUSEADDR, one);
93     if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) {
94         ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p,
95                     "make_sock: for address %pI, setsockopt: (SO_REUSEADDR)", 
96                      server->bind_addr);
97         apr_socket_close(s);
98         return stat;
99     }
100     
101     stat = apr_setsocketopt(s, APR_SO_KEEPALIVE, one);
102     if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) {
103         ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p,
104                     "make_sock: for address %pI, setsockopt: (SO_KEEPALIVE)", 
105                      server->bind_addr);
106         apr_socket_close(s);
107         return stat;
108     }
109
110     /*
111      * To send data over high bandwidth-delay connections at full
112      * speed we must force the TCP window to open wide enough to keep the
113      * pipe full.  The default window size on many systems
114      * is only 4kB.  Cross-country WAN connections of 100ms
115      * at 1Mb/s are not impossible for well connected sites.
116      * If we assume 100ms cross-country latency,
117      * a 4kB buffer limits throughput to 40kB/s.
118      *
119      * To avoid this problem I've added the SendBufferSize directive
120      * to allow the web master to configure send buffer size.
121      *
122      * The trade-off of larger buffers is that more kernel memory
123      * is consumed.  YMMV, know your customers and your network!
124      *
125      * -John Heidemann <johnh@isi.edu> 25-Oct-96
126      *
127      * If no size is specified, use the kernel default.
128      */
129     if (send_buffer_size) {
130         stat = apr_setsocketopt(s, APR_SO_SNDBUF,  send_buffer_size);
131         if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) {
132             ap_log_perror(APLOG_MARK, APLOG_WARNING, stat, p,
133                         "make_sock: failed to set SendBufferSize for "
134                          "address %pI, using default", 
135                          server->bind_addr);
136             /* not a fatal error */
137         }
138     }
139
140 #if APR_TCP_NODELAY_INHERITED
141     ap_sock_disable_nagle(s);
142 #endif
143
144     if ((stat = apr_bind(s, server->bind_addr)) != APR_SUCCESS) {
145         ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p,
146                      "make_sock: could not bind to address %pI", 
147                      server->bind_addr);
148         apr_socket_close(s);
149         return stat;
150     }
151
152     if ((stat = apr_listen(s, ap_listenbacklog)) != APR_SUCCESS) {
153         ap_log_perror(APLOG_MARK, APLOG_ERR, stat, p,
154             "make_sock: unable to listen for connections on address %pI", 
155                      server->bind_addr);
156         apr_socket_close(s);
157         return stat;
158     }
159
160 #ifdef APR_HAS_SO_ACCEPTFILTER
161 #ifndef ACCEPT_FILTER_NAME
162 #define ACCEPT_FILTER_NAME "dataready"
163 #endif
164     apr_socket_accept_filter(s, ACCEPT_FILTER_NAME, "");
165 #endif
166
167     server->sd = s;
168     server->active = 1;
169     return APR_SUCCESS;
170 }
171
172 static apr_status_t close_listeners_on_exec(void *v)
173 {
174     ap_listen_rec *lr;
175
176     for (lr = ap_listeners; lr; lr = lr->next) {
177         apr_socket_close(lr->sd);
178         lr->active = 0;
179     }
180     return APR_SUCCESS;
181 }
182
183
184 static void find_default_family(apr_pool_t *p)
185 {
186 #if APR_HAVE_IPV6
187     /* We know the platform supports IPv6, but this particular
188      * system may not have IPv6 enabled.  See if we can get an
189      * AF_INET6 socket.
190      */
191     if (default_family == APR_UNSPEC) {
192         apr_socket_t *tmp_sock;
193
194         if (apr_socket_create(&tmp_sock, APR_INET6, SOCK_STREAM,
195                               p) == APR_SUCCESS) {
196             apr_socket_close(tmp_sock);
197             default_family = APR_INET6;
198         }
199         else {
200             default_family = APR_INET;
201         }
202     }
203 #endif
204 }
205
206
207 static void alloc_listener(process_rec *process, char *addr, apr_port_t port)
208 {
209     ap_listen_rec **walk;
210     ap_listen_rec *new;
211     apr_status_t status;
212     char *oldaddr;
213     apr_port_t oldport;
214     apr_sockaddr_t *sa;
215
216     if (!addr) { /* don't bind to specific interface */
217         find_default_family(process->pool);
218         switch(default_family) {
219         case APR_INET:
220             addr = "0.0.0.0";
221             break;
222 #if APR_HAVE_IPV6
223         case APR_INET6:
224             addr = "::";
225             break;
226 #endif
227         default:
228             ap_assert(1 != 1); /* should not occur */
229         }
230     }
231
232     /* see if we've got an old listener for this address:port */
233     for (walk = &old_listeners; *walk; walk = &(*walk)->next) {
234         sa = (*walk)->bind_addr;
235         apr_sockaddr_port_get(&oldport, sa);
236         apr_sockaddr_ip_get(&oldaddr, sa);
237         if (!strcmp(oldaddr, addr) && port == oldport) {
238             /* re-use existing record */
239             new = *walk;
240             *walk = new->next;
241             new->next = ap_listeners;
242             ap_listeners = new;
243             return;
244         }
245     }
246
247     /* this has to survive restarts */
248     new = apr_palloc(process->pool, sizeof(ap_listen_rec));
249     new->active = 0;
250     if ((status = apr_sockaddr_info_get(&new->bind_addr, addr, APR_UNSPEC, port, 0, 
251                                   process->pool)) != APR_SUCCESS) {
252         ap_log_perror(APLOG_MARK, APLOG_CRIT, status, process->pool,
253                      "alloc_listener: failed to set up sockaddr for %s", addr);
254         return;
255     }
256     if ((status = apr_socket_create(&new->sd, new->bind_addr->sa.sin.sin_family, 
257                                     SOCK_STREAM, process->pool)) != APR_SUCCESS) {
258         ap_log_perror(APLOG_MARK, APLOG_CRIT, status, process->pool,
259                      "alloc_listener: failed to get a socket for %s", addr);
260         return;
261     }
262     apr_socket_set_inherit(new->sd);
263     new->next = ap_listeners;
264     ap_listeners = new;
265 }
266
267 #if !defined(SPMT_OS2_MPM)
268 static
269 #endif
270 int ap_listen_open(process_rec *process, apr_port_t port)
271 {
272     apr_pool_t *pconf = process->pconf;
273     ap_listen_rec *lr;
274     ap_listen_rec *next;
275     int num_open;
276
277     /* allocate a default listener if necessary */
278     if (ap_listeners == NULL) {
279         alloc_listener(process, NULL, port ? port : DEFAULT_HTTP_PORT);
280     }
281
282     num_open = 0;
283     for (lr = ap_listeners; lr; lr = lr->next) {
284         if (lr->active) {
285             ++num_open;
286         }
287         else {
288             if (make_sock(pconf, lr) == APR_SUCCESS) {
289                 ++num_open;
290                 lr->active = 1;
291             }
292         }
293     }
294
295     /* close the old listeners */
296     for (lr = old_listeners; lr; lr = next) {
297         apr_socket_close(lr->sd);
298         lr->active = 0;
299         next = lr->next;
300 /*      free(lr);*/
301     }
302     old_listeners = NULL;
303
304     apr_pool_cleanup_register(pconf, NULL, apr_pool_cleanup_null, close_listeners_on_exec);
305
306     return num_open ? 0 : -1;
307 }
308
309 int ap_setup_listeners(server_rec *s)
310 {
311     ap_listen_rec *lr;
312     int num_listeners = 0;
313     if (ap_listen_open(s->process, s->port)) {
314        return 0;
315     }
316     for (lr = ap_listeners; lr; lr = lr->next) {
317         num_listeners++;
318     }
319     return num_listeners;
320 }
321
322 void ap_listen_pre_config(void)
323 {
324     old_listeners = ap_listeners;
325     ap_listeners = NULL;
326     ap_listenbacklog = DEFAULT_LISTENBACKLOG;
327 }
328
329
330 const char *ap_set_listener(cmd_parms *cmd, void *dummy, const char *ips)
331 {
332     char *host, *scope_id;
333     apr_port_t port;
334     apr_status_t rv;
335
336     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
337     if (err != NULL) {
338         return err;
339     }
340
341     rv = apr_parse_addr_port(&host, &scope_id, &port, ips, cmd->pool);
342     if (rv != APR_SUCCESS) {
343         return "Invalid address or port";
344     }
345     if (host && !strcmp(host, "*")) {
346         host = NULL;
347     }
348     if (scope_id) {
349         /* XXX scope id support is useful with link-local IPv6 addresses */
350         return "Scope id is not supported";
351     }
352     if (!port) {
353         return "Port must be specified";
354     }
355
356     alloc_listener(cmd->server->process, host, port);
357
358     return NULL;
359 }
360
361 const char *ap_set_listenbacklog(cmd_parms *cmd, void *dummy, const char *arg) 
362 {
363     int b;
364
365     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
366     if (err != NULL) {
367         return err;
368     }
369
370     b = atoi(arg);
371     if (b < 1) {
372         return "ListenBacklog must be > 0";
373     }
374     ap_listenbacklog = b;
375     return NULL;
376 }
377
378 const char *ap_set_send_buffer_size(cmd_parms *cmd, void *dummy, const char *arg)
379 {
380     int s = atoi(arg);
381     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
382     if (err != NULL) {
383         return err;
384     }
385
386     if (s < 512 && s != 0) {
387         return "SendBufferSize must be >= 512 bytes, or 0 for system default.";
388     }
389     send_buffer_size = s;
390     return NULL;
391 }