1 /* Copyright 1999-2004 The Apache Software Foundation
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
16 #include "apr_network_io.h"
17 #include "apr_strings.h"
19 #define APR_WANT_STRFUNC
23 #include "ap_config.h"
25 #include "http_config.h"
26 #include "ap_listen.h"
29 #include "mpm_common.h"
31 AP_DECLARE_DATA ap_listen_rec *ap_listeners = NULL;
33 static ap_listen_rec *old_listeners;
34 static int ap_listenbacklog;
35 static int send_buffer_size;
37 /* TODO: make_sock is just begging and screaming for APR abstraction */
38 static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server)
40 apr_socket_t *s = server->sd;
43 #ifdef AP_ENABLE_V4_MAPPED
44 int v6only_setting = 0;
46 int v6only_setting = 1;
52 stat = apr_socket_opt_set(s, APR_SO_REUSEADDR, one);
53 if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) {
54 ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p,
55 "make_sock: for address %pI, apr_socket_opt_set: (SO_REUSEADDR)",
62 stat = apr_socket_opt_set(s, APR_SO_KEEPALIVE, one);
63 if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) {
64 ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p,
65 "make_sock: for address %pI, apr_socket_opt_set: (SO_KEEPALIVE)",
72 if (server->bind_addr->family == APR_INET6) {
73 stat = apr_socket_opt_set(s, APR_IPV6_V6ONLY, v6only_setting);
74 if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) {
75 ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p,
76 "make_sock: for address %pI, apr_socket_opt_set: "
86 * To send data over high bandwidth-delay connections at full
87 * speed we must force the TCP window to open wide enough to keep the
88 * pipe full. The default window size on many systems
89 * is only 4kB. Cross-country WAN connections of 100ms
90 * at 1Mb/s are not impossible for well connected sites.
91 * If we assume 100ms cross-country latency,
92 * a 4kB buffer limits throughput to 40kB/s.
94 * To avoid this problem I've added the SendBufferSize directive
95 * to allow the web master to configure send buffer size.
97 * The trade-off of larger buffers is that more kernel memory
98 * is consumed. YMMV, know your customers and your network!
100 * -John Heidemann <johnh@isi.edu> 25-Oct-96
102 * If no size is specified, use the kernel default.
104 if (send_buffer_size) {
105 stat = apr_socket_opt_set(s, APR_SO_SNDBUF, send_buffer_size);
106 if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) {
107 ap_log_perror(APLOG_MARK, APLOG_WARNING, stat, p,
108 "make_sock: failed to set SendBufferSize for "
109 "address %pI, using default",
111 /* not a fatal error */
115 #if APR_TCP_NODELAY_INHERITED
116 ap_sock_disable_nagle(s);
119 if ((stat = apr_socket_bind(s, server->bind_addr)) != APR_SUCCESS) {
120 ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT, stat, p,
121 "make_sock: could not bind to address %pI",
127 if ((stat = apr_socket_listen(s, ap_listenbacklog)) != APR_SUCCESS) {
128 ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_ERR, stat, p,
129 "make_sock: unable to listen for connections "
137 /* I seriously doubt that this would work on Unix; I have doubts that
138 * it entirely solves the problem on Win32. However, since setting
139 * reuseaddr on the listener -prior- to binding the socket has allowed
140 * us to attach to the same port as an already running instance of
141 * Apache, or even another web server, we cannot identify that this
142 * port was exclusively granted to this instance of Apache.
144 * So set reuseaddr, but do not attempt to do so until we have the
145 * parent listeners successfully bound.
147 stat = apr_socket_opt_set(s, APR_SO_REUSEADDR, one);
148 if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) {
149 ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p,
150 "make_sock: for address %pI, apr_socket_opt_set: (SO_REUSEADDR)",
157 #if APR_HAS_SO_ACCEPTFILTER
158 #ifndef ACCEPT_FILTER_NAME
159 #define ACCEPT_FILTER_NAME "httpready"
160 #ifdef __FreeBSD_version
161 #if __FreeBSD_version < 411000 /* httpready broken before 4.1.1 */
162 #undef ACCEPT_FILTER_NAME
163 #define ACCEPT_FILTER_NAME "dataready"
167 apr_socket_accept_filter(s, ACCEPT_FILTER_NAME, "");
173 #ifdef MPM_ACCEPT_FUNC
174 server->accept_func = MPM_ACCEPT_FUNC;
176 server->accept_func = NULL;
182 static apr_status_t close_listeners_on_exec(void *v)
186 for (lr = ap_listeners; lr; lr = lr->next) {
187 apr_socket_close(lr->sd);
195 static const char *alloc_listener(process_rec *process, char *addr, apr_port_t port)
197 ap_listen_rec **walk, *last;
200 int found_listener = 0;
202 /* see if we've got an old listener for this address:port */
203 for (walk = &old_listeners; *walk;) {
204 sa = (*walk)->bind_addr;
205 /* Some listeners are not real so they will not have a bind_addr. */
211 /* If both ports are equivalent, then if their names are equivalent,
212 * then we will re-use the existing record.
214 if (port == oldport &&
215 ((!addr && !sa->hostname) ||
216 ((addr && sa->hostname) && !strcmp(sa->hostname, addr)))) {
219 new->next = ap_listeners;
226 walk = &(*walk)->next;
229 if (found_listener) {
233 if ((status = apr_sockaddr_info_get(&sa, addr, APR_UNSPEC, port, 0,
236 ap_log_perror(APLOG_MARK, APLOG_CRIT, status, process->pool,
237 "alloc_listener: failed to set up sockaddr for %s",
239 return "Listen setup failed";
242 /* Initialize to our last configured ap_listener. */
244 while (last && last->next) {
251 /* this has to survive restarts */
252 new = apr_palloc(process->pool, sizeof(ap_listen_rec));
257 /* Go to the next sockaddr. */
260 status = apr_socket_create(&new->sd, new->bind_addr->family,
261 SOCK_STREAM, 0, process->pool);
264 /* What could happen is that we got an IPv6 address, but this system
265 * doesn't actually support IPv6. Try the next address.
267 if (status != APR_SUCCESS && !addr &&
268 new->bind_addr->family == APR_INET6) {
272 if (status != APR_SUCCESS) {
273 ap_log_perror(APLOG_MARK, APLOG_CRIT, status, process->pool,
274 "alloc_listener: failed to get a socket for %s",
276 return "Listen setup failed";
279 /* We need to preserve the order returned by getaddrinfo() */
281 ap_listeners = last = new;
291 AP_DECLARE(int) ap_listen_open(apr_pool_t *pool, apr_port_t port)
295 ap_listen_rec *previous;
297 const char *userdata_key = "ap_listen_open";
300 /* Don't allocate a default listener. If we need to listen to a
301 * port, then the user needs to have a Listen directive in their
306 for (lr = ap_listeners; lr; previous = lr, lr = lr->next) {
313 /* If we are trying to bind to 0.0.0.0 and the previous listener
314 * was :: on the same port and in turn that socket does not have
315 * the IPV6_V6ONLY flag set; we must skip the current attempt to
316 * listen (which would generate an error). IPv4 will be handled
317 * on the established IPv6 socket.
319 if (previous != NULL &&
320 lr->bind_addr->family == APR_INET &&
321 lr->bind_addr->sa.sin.sin_addr.s_addr == INADDR_ANY &&
322 lr->bind_addr->port == previous->bind_addr->port &&
323 previous->bind_addr->family == APR_INET6 &&
324 IN6_IS_ADDR_UNSPECIFIED(
325 &previous->bind_addr->sa.sin6.sin6_addr) &&
326 apr_socket_opt_get(previous->sd, APR_IPV6_V6ONLY,
327 &v6only_setting) == APR_SUCCESS &&
328 v6only_setting == 0) {
330 /* Remove the current listener from the list */
331 previous->next = lr->next;
335 if (make_sock(pool, lr) == APR_SUCCESS) {
341 /* If we tried to bind to ::, and the next listener is
342 * on 0.0.0.0 with the same port, don't give a fatal
343 * error. The user will still get a warning from make_sock
346 if (lr->next != NULL && lr->bind_addr->family == APR_INET6 &&
347 IN6_IS_ADDR_UNSPECIFIED(
348 &lr->bind_addr->sa.sin6.sin6_addr) &&
349 lr->bind_addr->port == lr->next->bind_addr->port &&
350 lr->next->bind_addr->family == APR_INET &&
351 lr->next->bind_addr->sa.sin.sin_addr.s_addr == INADDR_ANY) {
353 /* Remove the current listener from the list */
355 previous->next = lr->next;
358 ap_listeners = lr->next;
361 /* Although we've removed ourselves from the list,
362 * we need to make sure that the next iteration won't
363 * consider "previous" a working IPv6 '::' socket.
364 * Changing the family is enough to make sure the
365 * conditions before make_sock() fail.
367 lr->bind_addr->family = AF_INET;
378 /* close the old listeners */
379 for (lr = old_listeners; lr; lr = next) {
380 apr_socket_close(lr->sd);
384 old_listeners = NULL;
386 #if AP_NONBLOCK_WHEN_MULTI_LISTEN
387 /* if multiple listening sockets, make them non-blocking so that
388 * if select()/poll() reports readability for a reset connection that
389 * is already forgotten about by the time we call accept, we won't
390 * be hung until another connection arrives on that port
392 if (ap_listeners && ap_listeners->next) {
393 for (lr = ap_listeners; lr; lr = lr->next) {
396 status = apr_socket_opt_set(lr->sd, APR_SO_NONBLOCK, 1);
397 if (status != APR_SUCCESS) {
398 ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_ERR, status, pool,
399 "ap_listen_open: unable to make socket non-blocking");
404 #endif /* AP_NONBLOCK_WHEN_MULTI_LISTEN */
406 /* we come through here on both passes of the open logs phase
407 * only register the cleanup once... otherwise we try to close
408 * listening sockets twice when cleaning up prior to exec
410 apr_pool_userdata_get(&data, userdata_key, pool);
412 apr_pool_userdata_set((const void *)1, userdata_key,
413 apr_pool_cleanup_null, pool);
414 apr_pool_cleanup_register(pool, NULL, apr_pool_cleanup_null,
415 close_listeners_on_exec);
418 return num_open ? 0 : -1;
421 AP_DECLARE(int) ap_setup_listeners(server_rec *s)
424 int num_listeners = 0;
426 if (ap_listen_open(s->process->pool, s->port)) {
430 for (lr = ap_listeners; lr; lr = lr->next) {
434 return num_listeners;
437 AP_DECLARE(void) ap_listen_pre_config(void)
439 old_listeners = ap_listeners;
441 ap_listenbacklog = DEFAULT_LISTENBACKLOG;
445 AP_DECLARE(const char *) ap_set_listener(cmd_parms *cmd, void *dummy, const char *ips)
447 char *host, *scope_id;
450 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
456 rv = apr_parse_addr_port(&host, &scope_id, &port, ips, cmd->pool);
457 if (rv != APR_SUCCESS) {
458 return "Invalid address or port";
461 if (host && !strcmp(host, "*")) {
466 /* XXX scope id support is useful with link-local IPv6 addresses */
467 return "Scope id is not supported";
471 return "Port must be specified";
474 return alloc_listener(cmd->server->process, host, port);
477 AP_DECLARE(const char *) ap_set_listenbacklog(cmd_parms *cmd, void *dummy, const char *arg)
480 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
488 return "ListenBacklog must be > 0";
491 ap_listenbacklog = b;
495 AP_DECLARE(const char *) ap_set_send_buffer_size(cmd_parms *cmd, void *dummy,
499 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
505 if (s < 512 && s != 0) {
506 return "SendBufferSize must be >= 512 bytes, or 0 for system default.";
509 send_buffer_size = s;