1 /* ====================================================================
2 * The Apache Software License, Version 1.1
4 * Copyright (c) 2000-2001 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"
75 ap_listen_rec *ap_listeners;
77 static int default_family = APR_UNSPEC;
79 static int default_family = APR_INET;
81 static ap_listen_rec *old_listeners;
82 static int ap_listenbacklog;
83 static int send_buffer_size;
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)
88 apr_socket_t *s = server->sd;
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)",
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)",
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.
119 * To avoid this problem I've added the SendBufferSize directive
120 * to allow the web master to configure send buffer size.
122 * The trade-off of larger buffers is that more kernel memory
123 * is consumed. YMMV, know your customers and your network!
125 * -John Heidemann <johnh@isi.edu> 25-Oct-96
127 * If no size is specified, use the kernel default.
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",
136 /* not a fatal error */
140 #if APR_TCP_NODELAY_INHERITED
141 ap_sock_disable_nagle(s);
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",
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",
160 #ifdef APR_HAS_SO_ACCEPTFILTER
161 #ifndef ACCEPT_FILTER_NAME
162 #define ACCEPT_FILTER_NAME "dataready"
164 apr_socket_accept_filter(s, ACCEPT_FILTER_NAME, "");
172 static apr_status_t close_listeners_on_exec(void *v)
176 for (lr = ap_listeners; lr; lr = lr->next) {
177 apr_socket_close(lr->sd);
184 static void find_default_family(apr_pool_t *p)
187 /* We know the platform supports IPv6, but this particular
188 * system may not have IPv6 enabled. See if we can get an
191 if (default_family == APR_UNSPEC) {
192 apr_socket_t *tmp_sock;
194 if (apr_socket_create(&tmp_sock, APR_INET6, SOCK_STREAM,
196 apr_socket_close(tmp_sock);
197 default_family = APR_INET6;
200 default_family = APR_INET;
207 static void alloc_listener(process_rec *process, char *addr, apr_port_t port)
209 ap_listen_rec **walk;
216 if (!addr) { /* don't bind to specific interface */
217 find_default_family(process->pool);
218 switch(default_family) {
228 ap_assert(1 != 1); /* should not occur */
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 */
241 new->next = ap_listeners;
247 /* this has to survive restarts */
248 new = apr_palloc(process->pool, sizeof(ap_listen_rec));
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);
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);
262 apr_socket_set_inherit(new->sd);
263 new->next = ap_listeners;
267 #if !defined(SPMT_OS2_MPM)
270 int ap_listen_open(process_rec *process, apr_port_t port)
272 apr_pool_t *pconf = process->pconf;
277 /* allocate a default listener if necessary */
278 if (ap_listeners == NULL) {
279 alloc_listener(process, NULL, port ? port : DEFAULT_HTTP_PORT);
283 for (lr = ap_listeners; lr; lr = lr->next) {
288 if (make_sock(pconf, lr) == APR_SUCCESS) {
295 /* close the old listeners */
296 for (lr = old_listeners; lr; lr = next) {
297 apr_socket_close(lr->sd);
302 old_listeners = NULL;
304 apr_pool_cleanup_register(pconf, NULL, apr_pool_cleanup_null, close_listeners_on_exec);
306 return num_open ? 0 : -1;
309 int ap_setup_listeners(server_rec *s)
312 int num_listeners = 0;
313 if (ap_listen_open(s->process, s->port)) {
316 for (lr = ap_listeners; lr; lr = lr->next) {
319 return num_listeners;
322 void ap_listen_pre_config(void)
324 old_listeners = ap_listeners;
326 ap_listenbacklog = DEFAULT_LISTENBACKLOG;
330 const char *ap_set_listener(cmd_parms *cmd, void *dummy, const char *ips)
332 char *host, *scope_id;
336 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
341 rv = apr_parse_addr_port(&host, &scope_id, &port, ips, cmd->pool);
342 if (rv != APR_SUCCESS) {
343 return "Invalid address or port";
345 if (host && !strcmp(host, "*")) {
349 /* XXX scope id support is useful with link-local IPv6 addresses */
350 return "Scope id is not supported";
353 return "Port must be specified";
356 alloc_listener(cmd->server->process, host, port);
361 const char *ap_set_listenbacklog(cmd_parms *cmd, void *dummy, const char *arg)
365 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
372 return "ListenBacklog must be > 0";
374 ap_listenbacklog = b;
378 const char *ap_set_send_buffer_size(cmd_parms *cmd, void *dummy, const char *arg)
381 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
386 if (s < 512 && s != 0) {
387 return "SendBufferSize must be >= 512 bytes, or 0 for system default.";
389 send_buffer_size = s;