]> granicus.if.org Git - apache/blob - server/listen.c
More fun with IPv6 Listen statements.
[apache] / server / listen.c
1 /* ====================================================================
2  * The Apache Software License, Version 1.1
3  *
4  * Copyright (c) 2000-2003 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 ap_listen_rec *ap_listeners = NULL;
75
76 static ap_listen_rec *old_listeners;
77 static int ap_listenbacklog;
78 static int send_buffer_size;
79
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)
82 {
83     apr_socket_t *s = server->sd;
84     int one = 1;
85 #if APR_HAVE_IPV6
86 #ifdef AP_ENABLE_V4_MAPPED
87     int v6only_setting = 0;
88 #else
89     int v6only_setting = 1;
90 #endif
91 #endif
92     apr_status_t stat;
93
94 #ifndef WIN32
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)",
99                       server->bind_addr);
100         apr_socket_close(s);
101         return stat;
102     }
103 #endif
104
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)",
109                       server->bind_addr);
110         apr_socket_close(s);
111         return stat;
112     }
113
114 #if APR_HAVE_IPV6
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: "
120                           "(IPV6_V6ONLY)",
121                           server->bind_addr);
122             apr_socket_close(s);
123             return stat;
124         }
125     }
126 #endif
127
128     /*
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.
136      *
137      * To avoid this problem I've added the SendBufferSize directive
138      * to allow the web master to configure send buffer size.
139      *
140      * The trade-off of larger buffers is that more kernel memory
141      * is consumed.  YMMV, know your customers and your network!
142      *
143      * -John Heidemann <johnh@isi.edu> 25-Oct-96
144      *
145      * If no size is specified, use the kernel default.
146      */
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",
153                           server->bind_addr);
154             /* not a fatal error */
155         }
156     }
157
158 #if APR_TCP_NODELAY_INHERITED
159     ap_sock_disable_nagle(s);
160 #endif
161
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",
165                       server->bind_addr);
166         apr_socket_close(s);
167         return stat;
168     }
169
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 "
173                       "on address %pI",
174                       server->bind_addr);
175         apr_socket_close(s);
176         return stat;
177     }
178
179 #ifdef WIN32
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.
186      *
187      * So set reuseaddr, but do not attempt to do so until we have the
188      * parent listeners successfully bound.
189      */
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)", 
194                      server->bind_addr);
195         apr_socket_close(s);
196         return stat;
197     }
198 #endif
199
200 #if APR_HAS_SO_ACCEPTFILTER
201 #ifndef ACCEPT_FILTER_NAME
202 #define ACCEPT_FILTER_NAME "dataready"
203 #endif
204     apr_socket_accept_filter(s, ACCEPT_FILTER_NAME, "");
205 #endif
206
207     server->sd = s;
208     server->active = 1;
209
210 #ifdef MPM_ACCEPT_FUNC
211     server->accept_func = MPM_ACCEPT_FUNC;
212 #else
213     server->accept_func = NULL;
214 #endif
215
216     return APR_SUCCESS;
217 }
218
219 static apr_status_t close_listeners_on_exec(void *v)
220 {
221     ap_listen_rec *lr;
222
223     for (lr = ap_listeners; lr; lr = lr->next) {
224         apr_socket_close(lr->sd);
225         lr->active = 0;
226     }
227
228     return APR_SUCCESS;
229 }
230
231
232 static const char *alloc_listener(process_rec *process, char *addr, apr_port_t port)
233 {
234     ap_listen_rec **walk;
235     ap_listen_rec *new;
236     apr_status_t status;
237     apr_port_t oldport;
238     apr_sockaddr_t *sa;
239
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. */
244         if (sa) {
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.
248              */
249             if (port == oldport &&
250                 ((!addr && !sa->hostname) ||
251                  ((addr && sa->hostname) && !strcmp(sa->hostname, addr)))) {
252                 new = *walk;
253                 *walk = new->next;
254                 new->next = ap_listeners;
255                 ap_listeners = new;
256                 return NULL;
257             }
258         }
259     }
260
261     /* this has to survive restarts */
262     new = apr_palloc(process->pool, sizeof(ap_listen_rec));
263     new->active = 0;
264     if ((status = apr_sockaddr_info_get(&new->bind_addr, addr, APR_UNSPEC,
265                                         port, 0, process->pool))
266         != APR_SUCCESS) {
267         ap_log_perror(APLOG_MARK, APLOG_CRIT, status, process->pool,
268                       "alloc_listener: failed to set up sockaddr for %s",
269                       addr);
270         return "Listen setup failed";
271     }
272
273     while (new->bind_addr) {
274         status = apr_socket_create(&new->sd, new->bind_addr->family,
275                                     SOCK_STREAM, process->pool);
276 #if APR_HAVE_IPV6
277         /* What could happen is that we got an IPv6 address, but this system
278          * doesn't actually support IPv6.  Try the next address.
279          */
280         if (status != APR_SUCCESS && !addr &&
281             new->bind_addr->family == APR_INET6) {
282             new->bind_addr = new->bind_addr->next;
283         }
284         else {
285             break;
286         }
287 #else
288         break;
289 #endif
290     }
291
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";
296     }
297
298     new->next = ap_listeners;
299     ap_listeners = new;
300     return NULL;
301 }
302
303 static int ap_listen_open(apr_pool_t *pool, apr_port_t port)
304 {
305     ap_listen_rec *lr;
306     ap_listen_rec *next;
307     int num_open;
308     const char *userdata_key = "ap_listen_open";
309     void *data;
310
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
313      * config file.
314      */
315     num_open = 0;
316     for (lr = ap_listeners; lr; lr = lr->next) {
317         if (lr->active) {
318             ++num_open;
319         }
320         else {
321             if (make_sock(pool, lr) == APR_SUCCESS) {
322                 ++num_open;
323                 lr->active = 1;
324             }
325             else {
326                 /* fatal error */
327                 return -1;
328             }
329         }
330     }
331
332     /* close the old listeners */
333     for (lr = old_listeners; lr; lr = next) {
334         apr_socket_close(lr->sd);
335         lr->active = 0;
336         next = lr->next;
337     }
338     old_listeners = NULL;
339
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
343      */
344     apr_pool_userdata_get(&data, userdata_key, pool);
345     if (!data) {
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);
350     }
351
352     return num_open ? 0 : -1;
353 }
354
355 int ap_setup_listeners(server_rec *s)
356 {
357     ap_listen_rec *lr;
358     int num_listeners = 0;
359
360     if (ap_listen_open(s->process->pool, s->port)) {
361        return 0;
362     }
363
364     for (lr = ap_listeners; lr; lr = lr->next) {
365         num_listeners++;
366     }
367
368     return num_listeners;
369 }
370
371 void ap_listen_pre_config(void)
372 {
373     old_listeners = ap_listeners;
374     ap_listeners = NULL;
375     ap_listenbacklog = DEFAULT_LISTENBACKLOG;
376 }
377
378
379 const char *ap_set_listener(cmd_parms *cmd, void *dummy, const char *ips)
380 {
381     char *host, *scope_id;
382     apr_port_t port;
383     apr_status_t rv;
384     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
385
386     if (err != NULL) {
387         return err;
388     }
389
390     rv = apr_parse_addr_port(&host, &scope_id, &port, ips, cmd->pool);
391     if (rv != APR_SUCCESS) {
392         return "Invalid address or port";
393     }
394
395     if (host && !strcmp(host, "*")) {
396         host = NULL;
397     }
398
399     if (scope_id) {
400         /* XXX scope id support is useful with link-local IPv6 addresses */
401         return "Scope id is not supported";
402     }
403
404     if (!port) {
405         return "Port must be specified";
406     }
407
408     return alloc_listener(cmd->server->process, host, port);
409 }
410
411 const char *ap_set_listenbacklog(cmd_parms *cmd, void *dummy, const char *arg)
412 {
413     int b;
414     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
415
416     if (err != NULL) {
417         return err;
418     }
419
420     b = atoi(arg);
421     if (b < 1) {
422         return "ListenBacklog must be > 0";
423     }
424
425     ap_listenbacklog = b;
426     return NULL;
427 }
428
429 const char *ap_set_send_buffer_size(cmd_parms *cmd, void *dummy,
430                                     const char *arg)
431 {
432     int s = atoi(arg);
433     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
434
435     if (err != NULL) {
436         return err;
437     }
438
439     if (s < 512 && s != 0) {
440         return "SendBufferSize must be >= 512 bytes, or 0 for system default.";
441     }
442
443     send_buffer_size = s;
444     return NULL;
445 }