]> granicus.if.org Git - apache/blob - server/listen.c
Fix a bug in how we select the IP for the POD to connect to for dummy
[apache] / server / listen.c
1 /* ====================================================================
2  * The Apache Software License, Version 1.1
3  *
4  * Copyright (c) 2000-2001 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 #include "apr_lock.h"
62
63 #define APR_WANT_STRFUNC
64 #include "apr_want.h"
65
66 #define CORE_PRIVATE
67 #include "ap_config.h"
68 #include "httpd.h"
69 #include "http_config.h"
70 #include "ap_listen.h"
71 #include "http_log.h"
72 #include "mpm.h"
73 #include "mpm_common.h"
74
75 ap_listen_rec *ap_listeners;
76 #if APR_HAVE_IPV6
77 static int default_family = APR_UNSPEC;
78 #else
79 static int default_family = APR_INET;
80 #endif
81 static ap_listen_rec *old_listeners;
82 static int ap_listenbacklog;
83 static int send_buffer_size;
84
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)
87 {
88     apr_socket_t *s = server->sd;
89     int one = 1;
90     apr_status_t stat;
91
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)", 
96                      server->bind_addr);
97         apr_socket_close(s);
98         return stat;
99     }
100     
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)", 
105                      server->bind_addr);
106         apr_socket_close(s);
107         return stat;
108     }
109
110     /*
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.
118      *
119      * To avoid this problem I've added the SendBufferSize directive
120      * to allow the web master to configure send buffer size.
121      *
122      * The trade-off of larger buffers is that more kernel memory
123      * is consumed.  YMMV, know your customers and your network!
124      *
125      * -John Heidemann <johnh@isi.edu> 25-Oct-96
126      *
127      * If no size is specified, use the kernel default.
128      */
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", 
135                          server->bind_addr);
136             /* not a fatal error */
137         }
138     }
139
140 #if APR_TCP_NODELAY_INHERITED
141     ap_sock_disable_nagle(s);
142 #endif
143
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", 
147                      server->bind_addr);
148         apr_socket_close(s);
149         return stat;
150     }
151
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", 
155                      server->bind_addr);
156         apr_socket_close(s);
157         return stat;
158     }
159
160 #if APR_HAS_SO_ACCEPTFILTER
161 #ifndef ACCEPT_FILTER_NAME
162 #define ACCEPT_FILTER_NAME "dataready"
163 #endif
164     apr_socket_accept_filter(s, ACCEPT_FILTER_NAME, "");
165 #endif
166
167     server->sd = s;
168     server->active = 1;
169 #ifdef MPM_ACCEPT_FUNC
170     server->accept_func = MPM_ACCEPT_FUNC;
171 #else
172     server->accept_func = NULL;
173 #endif
174     return APR_SUCCESS;
175 }
176
177 static apr_status_t close_listeners_on_exec(void *v)
178 {
179     ap_listen_rec *lr;
180
181     for (lr = ap_listeners; lr; lr = lr->next) {
182         apr_socket_close(lr->sd);
183         lr->active = 0;
184     }
185     return APR_SUCCESS;
186 }
187
188
189 static void find_default_family(apr_pool_t *p)
190 {
191 #if APR_HAVE_IPV6
192     /* We know the platform supports IPv6, but this particular
193      * system may not have IPv6 enabled.  See if we can get an
194      * AF_INET6 socket.
195      */
196     if (default_family == APR_UNSPEC) {
197         apr_socket_t *tmp_sock;
198
199         if (apr_socket_create(&tmp_sock, APR_INET6, SOCK_STREAM,
200                               p) == APR_SUCCESS) {
201             apr_socket_close(tmp_sock);
202             default_family = APR_INET6;
203         }
204         else {
205             default_family = APR_INET;
206         }
207     }
208 #endif
209 }
210
211
212 static void alloc_listener(process_rec *process, char *addr, apr_port_t port)
213 {
214     ap_listen_rec **walk;
215     ap_listen_rec *new;
216     apr_status_t status;
217     char *oldaddr;
218     apr_port_t oldport;
219     apr_sockaddr_t *sa;
220
221     if (!addr) { /* don't bind to specific interface */
222         find_default_family(process->pool);
223         switch(default_family) {
224         case APR_INET:
225             addr = "0.0.0.0";
226             break;
227 #if APR_HAVE_IPV6
228         case APR_INET6:
229             addr = "::";
230             break;
231 #endif
232         default:
233             ap_assert(1 != 1); /* should not occur */
234         }
235     }
236
237     /* see if we've got an old listener for this address:port */
238     for (walk = &old_listeners; *walk; walk = &(*walk)->next) {
239         sa = (*walk)->bind_addr;
240         /* Some listeners are not real so they will not have a bind_addr. */
241         if (sa) {
242             apr_sockaddr_port_get(&oldport, sa);
243             apr_sockaddr_ip_get(&oldaddr, sa);
244             if (!strcmp(oldaddr, addr) && port == oldport) {
245                 /* re-use existing record */
246                 new = *walk;
247                 *walk = new->next;
248                 new->next = ap_listeners;
249                 ap_listeners = new;
250                 return;
251             }
252         }
253     }
254
255     /* this has to survive restarts */
256     new = apr_palloc(process->pool, sizeof(ap_listen_rec));
257     new->active = 0;
258     if ((status = apr_sockaddr_info_get(&new->bind_addr, addr, APR_UNSPEC, 
259                                       port, 0, process->pool)) != APR_SUCCESS) {
260         ap_log_perror(APLOG_MARK, APLOG_CRIT, status, process->pool,
261                      "alloc_listener: failed to set up sockaddr for %s", addr);
262         return;
263     }
264     if ((status = apr_socket_create(&new->sd, new->bind_addr->sa.sin.sin_family, 
265                                   SOCK_STREAM, process->pool)) != APR_SUCCESS) {
266         ap_log_perror(APLOG_MARK, APLOG_CRIT, status, process->pool,
267                      "alloc_listener: failed to get a socket for %s", addr);
268         return;
269     }
270     new->next = ap_listeners;
271     ap_listeners = new;
272 }
273
274 #if !defined(SPMT_OS2_MPM)
275 static
276 #endif
277 int ap_listen_open(process_rec *process, apr_port_t port)
278 {
279     apr_pool_t *pconf = process->pconf;
280     ap_listen_rec *lr;
281     ap_listen_rec *next;
282     int num_open;
283
284     /* Don't allocate a default listener.  If we need to listen to a
285      * port, then the user needs to have a Listen directive in their
286      * config file.
287      */
288     num_open = 0;
289     for (lr = ap_listeners; lr; lr = lr->next) {
290         if (lr->active) {
291             ++num_open;
292         }
293         else {
294             if (make_sock(pconf, lr) == APR_SUCCESS) {
295                 ++num_open;
296                 lr->active = 1;
297             }
298             else {
299                 /* fatal error */
300                 return -1;
301             }
302         }
303     }
304
305     /* close the old listeners */
306     for (lr = old_listeners; lr; lr = next) {
307         apr_socket_close(lr->sd);
308         lr->active = 0;
309         next = lr->next;
310         /*free(lr);*/
311     }
312     old_listeners = NULL;
313
314     apr_pool_cleanup_register(pconf, NULL, apr_pool_cleanup_null, 
315                               close_listeners_on_exec);
316
317     return num_open ? 0 : -1;
318 }
319
320 int ap_setup_listeners(server_rec *s)
321 {
322     ap_listen_rec *lr;
323     int num_listeners = 0;
324     if (ap_listen_open(s->process, s->port)) {
325        return 0;
326     }
327     for (lr = ap_listeners; lr; lr = lr->next) {
328         num_listeners++;
329     }
330     return num_listeners;
331 }
332
333 void ap_listen_pre_config(void)
334 {
335     old_listeners = ap_listeners;
336     ap_listeners = NULL;
337     ap_listenbacklog = DEFAULT_LISTENBACKLOG;
338 }
339
340
341 const char *ap_set_listener(cmd_parms *cmd, void *dummy, const char *ips)
342 {
343     char *host, *scope_id;
344     apr_port_t port;
345     apr_status_t rv;
346
347     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
348     if (err != NULL) {
349         return err;
350     }
351
352     rv = apr_parse_addr_port(&host, &scope_id, &port, ips, cmd->pool);
353     if (rv != APR_SUCCESS) {
354         return "Invalid address or port";
355     }
356     if (host && !strcmp(host, "*")) {
357         host = NULL;
358     }
359     if (scope_id) {
360         /* XXX scope id support is useful with link-local IPv6 addresses */
361         return "Scope id is not supported";
362     }
363     if (!port) {
364         return "Port must be specified";
365     }
366
367     alloc_listener(cmd->server->process, host, port);
368
369     return NULL;
370 }
371
372 const char *ap_set_listenbacklog(cmd_parms *cmd, void *dummy, const char *arg) 
373 {
374     int b;
375
376     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
377     if (err != NULL) {
378         return err;
379     }
380
381     b = atoi(arg);
382     if (b < 1) {
383         return "ListenBacklog must be > 0";
384     }
385     ap_listenbacklog = b;
386     return NULL;
387 }
388
389 const char *ap_set_send_buffer_size(cmd_parms *cmd, void *dummy, 
390                                     const char *arg)
391 {
392     int s = atoi(arg);
393     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
394     if (err != NULL) {
395         return err;
396     }
397
398     if (s < 512 && s != 0) {
399         return "SendBufferSize must be >= 512 bytes, or 0 for system default.";
400     }
401     send_buffer_size = s;
402     return NULL;
403 }