1 /* ====================================================================
2 * The Apache Software License, Version 1.1
4 * Copyright (c) 2000-2003 The Apache Software Foundation. All rights
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
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
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.
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.
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.
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
47 * ====================================================================
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/>.
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.
59 #include "apr_network_io.h"
60 #include "apr_strings.h"
62 #define APR_WANT_STRFUNC
66 #include "ap_config.h"
68 #include "http_config.h"
69 #include "ap_listen.h"
72 #include "mpm_common.h"
74 ap_listen_rec *ap_listeners = NULL;
76 static ap_listen_rec *old_listeners;
77 static int ap_listenbacklog;
78 static int send_buffer_size;
80 /* TODO: make_sock is just begging and screaming for APR abstraction */
81 static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server)
83 apr_socket_t *s = server->sd;
86 #ifdef AP_ENABLE_V4_MAPPED
87 int v6only_setting = 0;
89 int v6only_setting = 1;
95 stat = apr_socket_opt_set(s, APR_SO_REUSEADDR, one);
96 if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) {
97 ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p,
98 "make_sock: for address %pI, apr_socket_opt_set: (SO_REUSEADDR)",
105 stat = apr_socket_opt_set(s, APR_SO_KEEPALIVE, one);
106 if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) {
107 ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p,
108 "make_sock: for address %pI, apr_socket_opt_set: (SO_KEEPALIVE)",
115 if (server->bind_addr->family == APR_INET6) {
116 stat = apr_socket_opt_set(s, APR_IPV6_V6ONLY, v6only_setting);
117 if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) {
118 ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p,
119 "make_sock: for address %pI, apr_socket_opt_set: "
129 * To send data over high bandwidth-delay connections at full
130 * speed we must force the TCP window to open wide enough to keep the
131 * pipe full. The default window size on many systems
132 * is only 4kB. Cross-country WAN connections of 100ms
133 * at 1Mb/s are not impossible for well connected sites.
134 * If we assume 100ms cross-country latency,
135 * a 4kB buffer limits throughput to 40kB/s.
137 * To avoid this problem I've added the SendBufferSize directive
138 * to allow the web master to configure send buffer size.
140 * The trade-off of larger buffers is that more kernel memory
141 * is consumed. YMMV, know your customers and your network!
143 * -John Heidemann <johnh@isi.edu> 25-Oct-96
145 * If no size is specified, use the kernel default.
147 if (send_buffer_size) {
148 stat = apr_socket_opt_set(s, APR_SO_SNDBUF, send_buffer_size);
149 if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) {
150 ap_log_perror(APLOG_MARK, APLOG_WARNING, stat, p,
151 "make_sock: failed to set SendBufferSize for "
152 "address %pI, using default",
154 /* not a fatal error */
158 #if APR_TCP_NODELAY_INHERITED
159 ap_sock_disable_nagle(s);
162 if ((stat = apr_bind(s, server->bind_addr)) != APR_SUCCESS) {
163 ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT, stat, p,
164 "make_sock: could not bind to address %pI",
170 if ((stat = apr_listen(s, ap_listenbacklog)) != APR_SUCCESS) {
171 ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_ERR, stat, p,
172 "make_sock: unable to listen for connections "
180 /* I seriously doubt that this would work on Unix; I have doubts that
181 * it entirely solves the problem on Win32. However, since setting
182 * reuseaddr on the listener -prior- to binding the socket has allowed
183 * us to attach to the same port as an already running instance of
184 * Apache, or even another web server, we cannot identify that this
185 * port was exclusively granted to this instance of Apache.
187 * So set reuseaddr, but do not attempt to do so until we have the
188 * parent listeners successfully bound.
190 stat = apr_socket_opt_set(s, APR_SO_REUSEADDR, one);
191 if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) {
192 ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p,
193 "make_sock: for address %pI, apr_socket_opt_set: (SO_REUSEADDR)",
200 #if APR_HAS_SO_ACCEPTFILTER
201 #ifndef ACCEPT_FILTER_NAME
202 #define ACCEPT_FILTER_NAME "dataready"
204 apr_socket_accept_filter(s, ACCEPT_FILTER_NAME, "");
210 #ifdef MPM_ACCEPT_FUNC
211 server->accept_func = MPM_ACCEPT_FUNC;
213 server->accept_func = NULL;
219 static apr_status_t close_listeners_on_exec(void *v)
223 for (lr = ap_listeners; lr; lr = lr->next) {
224 apr_socket_close(lr->sd);
232 static const char *alloc_listener(process_rec *process, char *addr, apr_port_t port)
234 ap_listen_rec **walk;
240 /* see if we've got an old listener for this address:port */
241 for (walk = &old_listeners; *walk; walk = &(*walk)->next) {
242 sa = (*walk)->bind_addr;
243 /* Some listeners are not real so they will not have a bind_addr. */
245 apr_sockaddr_port_get(&oldport, sa);
246 /* If both ports are equivalent, then if their names are equivalent,
247 * then we will re-use the existing record.
249 if (port == oldport &&
250 ((!addr && !sa->hostname) ||
251 ((addr && sa->hostname) && !strcmp(sa->hostname, addr)))) {
254 new->next = ap_listeners;
261 /* this has to survive restarts */
262 new = apr_palloc(process->pool, sizeof(ap_listen_rec));
264 if ((status = apr_sockaddr_info_get(&new->bind_addr, addr, APR_UNSPEC,
265 port, 0, process->pool))
267 ap_log_perror(APLOG_MARK, APLOG_CRIT, status, process->pool,
268 "alloc_listener: failed to set up sockaddr for %s",
270 return "Listen setup failed";
273 while (new->bind_addr) {
274 status = apr_socket_create(&new->sd, new->bind_addr->family,
275 SOCK_STREAM, process->pool);
277 /* What could happen is that we got an IPv6 address, but this system
278 * doesn't actually support IPv6. Try the next address.
280 if (status != APR_SUCCESS && !addr &&
281 new->bind_addr->family == APR_INET6) {
282 new->bind_addr = new->bind_addr->next;
292 if (status != APR_SUCCESS) {
293 ap_log_perror(APLOG_MARK, APLOG_CRIT, status, process->pool,
294 "alloc_listener: failed to get a socket for %s", addr);
295 return "Listen setup failed";
298 new->next = ap_listeners;
303 static int ap_listen_open(apr_pool_t *pool, apr_port_t port)
308 const char *userdata_key = "ap_listen_open";
311 /* Don't allocate a default listener. If we need to listen to a
312 * port, then the user needs to have a Listen directive in their
316 for (lr = ap_listeners; lr; lr = lr->next) {
321 if (make_sock(pool, lr) == APR_SUCCESS) {
332 /* close the old listeners */
333 for (lr = old_listeners; lr; lr = next) {
334 apr_socket_close(lr->sd);
338 old_listeners = NULL;
340 /* we come through here on both passes of the open logs phase
341 * only register the cleanup once... otherwise we try to close
342 * listening sockets twice when cleaning up prior to exec
344 apr_pool_userdata_get(&data, userdata_key, pool);
346 apr_pool_userdata_set((const void *)1, userdata_key,
347 apr_pool_cleanup_null, pool);
348 apr_pool_cleanup_register(pool, NULL, apr_pool_cleanup_null,
349 close_listeners_on_exec);
352 return num_open ? 0 : -1;
355 int ap_setup_listeners(server_rec *s)
358 int num_listeners = 0;
360 if (ap_listen_open(s->process->pool, s->port)) {
364 for (lr = ap_listeners; lr; lr = lr->next) {
368 return num_listeners;
371 void ap_listen_pre_config(void)
373 old_listeners = ap_listeners;
375 ap_listenbacklog = DEFAULT_LISTENBACKLOG;
379 const char *ap_set_listener(cmd_parms *cmd, void *dummy, const char *ips)
381 char *host, *scope_id;
384 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
390 rv = apr_parse_addr_port(&host, &scope_id, &port, ips, cmd->pool);
391 if (rv != APR_SUCCESS) {
392 return "Invalid address or port";
395 if (host && !strcmp(host, "*")) {
400 /* XXX scope id support is useful with link-local IPv6 addresses */
401 return "Scope id is not supported";
405 return "Port must be specified";
408 return alloc_listener(cmd->server->process, host, port);
411 const char *ap_set_listenbacklog(cmd_parms *cmd, void *dummy, const char *arg)
414 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
422 return "ListenBacklog must be > 0";
425 ap_listenbacklog = b;
429 const char *ap_set_send_buffer_size(cmd_parms *cmd, void *dummy,
433 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
439 if (s < 512 && s != 0) {
440 return "SendBufferSize must be >= 512 bytes, or 0 for system default.";
443 send_buffer_size = s;