1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "apr_network_io.h"
18 #include "apr_strings.h"
20 #define APR_WANT_STRFUNC
24 #include "ap_config.h"
26 #include "http_config.h"
27 #include "ap_listen.h"
30 #include "mpm_common.h"
32 ap_listen_rec *ap_listeners = NULL;
35 static int default_family = APR_UNSPEC;
37 static int default_family = APR_INET;
40 static ap_listen_rec *old_listeners;
41 static int ap_listenbacklog;
42 static int send_buffer_size;
43 static int receive_buffer_size;
45 /* TODO: make_sock is just begging and screaming for APR abstraction */
46 static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server)
48 apr_socket_t *s = server->sd;
51 #ifdef AP_ENABLE_V4_MAPPED
52 int v6only_setting = 0;
54 int v6only_setting = 1;
60 stat = apr_socket_opt_set(s, APR_SO_REUSEADDR, one);
61 if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) {
62 ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p,
63 "make_sock: for address %pI, apr_socket_opt_set: (SO_REUSEADDR)",
70 stat = apr_socket_opt_set(s, APR_SO_KEEPALIVE, one);
71 if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) {
72 ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p,
73 "make_sock: for address %pI, apr_socket_opt_set: (SO_KEEPALIVE)",
80 if (server->bind_addr->family == APR_INET6) {
81 stat = apr_socket_opt_set(s, APR_IPV6_V6ONLY, v6only_setting);
82 if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) {
83 ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p,
84 "make_sock: for address %pI, apr_socket_opt_set: "
94 * To send data over high bandwidth-delay connections at full
95 * speed we must force the TCP window to open wide enough to keep the
96 * pipe full. The default window size on many systems
97 * is only 4kB. Cross-country WAN connections of 100ms
98 * at 1Mb/s are not impossible for well connected sites.
99 * If we assume 100ms cross-country latency,
100 * a 4kB buffer limits throughput to 40kB/s.
102 * To avoid this problem I've added the SendBufferSize directive
103 * to allow the web master to configure send buffer size.
105 * The trade-off of larger buffers is that more kernel memory
106 * is consumed. YMMV, know your customers and your network!
108 * -John Heidemann <johnh@isi.edu> 25-Oct-96
110 * If no size is specified, use the kernel default.
112 if (send_buffer_size) {
113 stat = apr_socket_opt_set(s, APR_SO_SNDBUF, send_buffer_size);
114 if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) {
115 ap_log_perror(APLOG_MARK, APLOG_WARNING, stat, p,
116 "make_sock: failed to set SendBufferSize for "
117 "address %pI, using default",
119 /* not a fatal error */
122 if (receive_buffer_size) {
123 stat = apr_socket_opt_set(s, APR_SO_RCVBUF, receive_buffer_size);
124 if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) {
125 ap_log_perror(APLOG_MARK, APLOG_WARNING, stat, p,
126 "make_sock: failed to set ReceiveBufferSize for "
127 "address %pI, using default",
129 /* not a fatal error */
133 #if APR_TCP_NODELAY_INHERITED
134 ap_sock_disable_nagle(s);
137 if ((stat = apr_bind(s, server->bind_addr)) != APR_SUCCESS) {
138 ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT, stat, p,
139 "make_sock: could not bind to address %pI",
145 if ((stat = apr_listen(s, ap_listenbacklog)) != APR_SUCCESS) {
146 ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_ERR, stat, p,
147 "make_sock: unable to listen for connections "
155 /* I seriously doubt that this would work on Unix; I have doubts that
156 * it entirely solves the problem on Win32. However, since setting
157 * reuseaddr on the listener -prior- to binding the socket has allowed
158 * us to attach to the same port as an already running instance of
159 * Apache, or even another web server, we cannot identify that this
160 * port was exclusively granted to this instance of Apache.
162 * So set reuseaddr, but do not attempt to do so until we have the
163 * parent listeners successfully bound.
165 stat = apr_socket_opt_set(s, APR_SO_REUSEADDR, one);
166 if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) {
167 ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p,
168 "make_sock: for address %pI, apr_socket_opt_set: (SO_REUSEADDR)",
175 #if APR_HAS_SO_ACCEPTFILTER
176 #ifndef ACCEPT_FILTER_NAME
177 #define ACCEPT_FILTER_NAME "httpready"
178 #ifdef __FreeBSD_version
179 #if __FreeBSD_version < 411000 /* httpready was broken before 4.1.1 */
180 #undef ACCEPT_FILTER_NAME
181 #define ACCEPT_FILTER_NAME "dataready"
185 apr_socket_accept_filter(s, ACCEPT_FILTER_NAME, "");
191 #ifdef MPM_ACCEPT_FUNC
192 server->accept_func = MPM_ACCEPT_FUNC;
194 server->accept_func = NULL;
200 static apr_status_t close_listeners_on_exec(void *v)
204 for (lr = ap_listeners; lr; lr = lr->next) {
205 apr_socket_close(lr->sd);
213 static void find_default_family(apr_pool_t *p)
216 /* We know the platform supports IPv6, but this particular
217 * system may not have IPv6 enabled. See if we can get an
218 * AF_INET6 socket and bind to an ephemeral port. (On most
219 * systems, getting an AF_INET6 socket is a sufficient test.
220 * On certain levels of OpenUNIX, getting the socket is
221 * successful but bind always returns ENETUNREACH.)
223 if (default_family == APR_UNSPEC) {
224 apr_status_t sock_rv;
225 apr_socket_t *tmp_sock;
228 if ((sock_rv = apr_socket_create(&tmp_sock, APR_INET6, SOCK_STREAM, p))
230 apr_sockaddr_info_get(&sa, NULL, APR_INET6, 0, 0, p) == APR_SUCCESS &&
231 apr_bind(tmp_sock, sa) == APR_SUCCESS) {
232 default_family = APR_INET6;
235 default_family = APR_INET;
237 if (sock_rv == APR_SUCCESS) {
238 apr_socket_close(tmp_sock);
245 static const char *alloc_listener(process_rec *process, char *addr, apr_port_t port)
247 ap_listen_rec **walk;
253 if (!addr) { /* don't bind to specific interface */
254 find_default_family(process->pool);
255 switch(default_family) {
267 ap_assert(1 != 1); /* should not occur */
271 /* see if we've got an old listener for this address:port */
272 for (walk = &old_listeners; *walk; walk = &(*walk)->next) {
273 sa = (*walk)->bind_addr;
274 /* Some listeners are not real so they will not have a bind_addr. */
276 apr_sockaddr_port_get(&oldport, sa);
277 if (!strcmp(sa->hostname, addr) && port == oldport) {
278 /* re-use existing record */
281 new->next = ap_listeners;
288 /* this has to survive restarts */
289 new = apr_palloc(process->pool, sizeof(ap_listen_rec));
291 if ((status = apr_sockaddr_info_get(&new->bind_addr, addr, APR_UNSPEC,
292 port, 0, process->pool))
294 ap_log_perror(APLOG_MARK, APLOG_CRIT, status, process->pool,
295 "alloc_listener: failed to set up sockaddr for %s",
297 return "Listen setup failed";
299 if ((status = apr_socket_create(&new->sd,
300 new->bind_addr->family,
301 SOCK_STREAM, process->pool))
303 ap_log_perror(APLOG_MARK, APLOG_CRIT, status, process->pool,
304 "alloc_listener: failed to get a socket for %s", addr);
305 return "Listen setup failed";
308 new->next = ap_listeners;
313 static int ap_listen_open(apr_pool_t *pool, apr_port_t port)
318 const char *userdata_key = "ap_listen_open";
321 /* Don't allocate a default listener. If we need to listen to a
322 * port, then the user needs to have a Listen directive in their
326 for (lr = ap_listeners; lr; lr = lr->next) {
331 if (make_sock(pool, lr) == APR_SUCCESS) {
342 /* close the old listeners */
343 for (lr = old_listeners; lr; lr = next) {
344 apr_socket_close(lr->sd);
348 old_listeners = NULL;
350 #if AP_NONBLOCK_WHEN_MULTI_LISTEN
351 /* if multiple listening sockets, make them non-blocking so that
352 * if select()/poll() reports readability for a reset connection that
353 * is already forgotten about by the time we call accept, we won't
354 * be hung until another connection arrives on that port
356 if (ap_listeners && ap_listeners->next) {
357 for (lr = ap_listeners; lr; lr = lr->next) {
360 status = apr_socket_opt_set(lr->sd, APR_SO_NONBLOCK, 1);
361 if (status != APR_SUCCESS) {
362 ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_ERR, status, pool,
363 "ap_listen_open: unable to make socket non-blocking");
368 #endif /* AP_NONBLOCK_WHEN_MULTI_LISTEN */
370 /* we come through here on both passes of the open logs phase
371 * only register the cleanup once... otherwise we try to close
372 * listening sockets twice when cleaning up prior to exec
374 apr_pool_userdata_get(&data, userdata_key, pool);
376 apr_pool_userdata_set((const void *)1, userdata_key,
377 apr_pool_cleanup_null, pool);
378 apr_pool_cleanup_register(pool, NULL, apr_pool_cleanup_null,
379 close_listeners_on_exec);
382 return num_open ? 0 : -1;
385 int ap_setup_listeners(server_rec *s)
388 int num_listeners = 0;
390 if (ap_listen_open(s->process->pool, s->port)) {
394 for (lr = ap_listeners; lr; lr = lr->next) {
398 return num_listeners;
401 void ap_listen_pre_config(void)
403 old_listeners = ap_listeners;
405 ap_listenbacklog = DEFAULT_LISTENBACKLOG;
409 const char *ap_set_listener(cmd_parms *cmd, void *dummy, const char *ips)
411 char *host, *scope_id;
414 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
420 rv = apr_parse_addr_port(&host, &scope_id, &port, ips, cmd->pool);
421 if (rv != APR_SUCCESS) {
422 return "Invalid address or port";
425 if (host && !strcmp(host, "*")) {
430 /* XXX scope id support is useful with link-local IPv6 addresses */
431 return "Scope id is not supported";
435 return "Port must be specified";
438 return alloc_listener(cmd->server->process, host, port);
441 const char *ap_set_listenbacklog(cmd_parms *cmd, void *dummy, const char *arg)
444 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
452 return "ListenBacklog must be > 0";
455 ap_listenbacklog = b;
459 const char *ap_set_send_buffer_size(cmd_parms *cmd, void *dummy,
463 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
469 if (s < 512 && s != 0) {
470 return "SendBufferSize must be >= 512 bytes, or 0 for system default.";
473 send_buffer_size = s;
477 AP_DECLARE_NONSTD(const char *) ap_set_receive_buffer_size(cmd_parms *cmd,
482 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
488 if (s < 512 && s != 0) {
489 return "ReceiveBufferSize must be >= 512 bytes, or 0 for system default.";
492 receive_buffer_size = s;