]> granicus.if.org Git - apache/blob - server/listen.c
Include mpm.h so that we know which MPM is being built and therefore
[apache] / server / listen.c
1 /* ====================================================================
2  * The Apache Software License, Version 1.1
3  *
4  * Copyright (c) 2000 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
61 #define CORE_PRIVATE
62 #include "ap_config.h"
63 #include "httpd.h"
64 #include "http_config.h"
65 #include "ap_listen.h"
66 #include "apr_strings.h"
67 #include "http_log.h"
68 #include "mpm.h"
69 #include "mpm_common.h"
70 #ifdef HAVE_STRING_H
71 #include <string.h>
72 #endif
73
74 ap_listen_rec *ap_listeners;
75 static ap_listen_rec *old_listeners;
76 static int ap_listenbacklog;
77 static int send_buffer_size;
78
79 /* TODO: make_sock is just begging and screaming for APR abstraction */
80 static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server)
81 {
82     apr_socket_t *s = server->sd;
83     int one = 1;
84     char addr[512];
85     apr_status_t stat;
86     apr_port_t port;
87     char *ipaddr;
88     apr_sockaddr_t *localsa;
89
90     apr_get_sockaddr(&localsa, APR_LOCAL, s);
91     apr_get_port(&port, localsa);
92     apr_get_ipaddr(&ipaddr, localsa);
93     apr_snprintf(addr, sizeof(addr), "address %s port %u", ipaddr,
94                 (unsigned) port);
95
96     stat = apr_getaddrinfo(&localsa, ipaddr, APR_INET, port, 0, p);
97     if (stat != APR_SUCCESS) {
98         ap_log_error(APLOG_MARK, APLOG_CRIT, stat, NULL,
99                      "make_sock: for %s/%hu, apr_getaddrinfo() failed", 
100                      ipaddr, port);
101         apr_close_socket(s);
102         return stat;
103     }
104
105     stat = apr_setsocketopt(s, APR_SO_REUSEADDR, one);
106     if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) {
107         ap_log_error(APLOG_MARK, APLOG_CRIT, stat, NULL,
108                     "make_sock: for %s, setsockopt: (SO_REUSEADDR)", addr);
109         apr_close_socket(s);
110         return stat;
111     }
112     
113     stat = apr_setsocketopt(s, APR_SO_KEEPALIVE, one);
114     if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) {
115         ap_log_error(APLOG_MARK, APLOG_CRIT, stat, NULL,
116                     "make_sock: for %s, setsockopt: (SO_KEEPALIVE)", addr);
117         apr_close_socket(s);
118         return stat;
119     }
120
121     /*
122      * To send data over high bandwidth-delay connections at full
123      * speed we must force the TCP window to open wide enough to keep the
124      * pipe full.  The default window size on many systems
125      * is only 4kB.  Cross-country WAN connections of 100ms
126      * at 1Mb/s are not impossible for well connected sites.
127      * If we assume 100ms cross-country latency,
128      * a 4kB buffer limits throughput to 40kB/s.
129      *
130      * To avoid this problem I've added the SendBufferSize directive
131      * to allow the web master to configure send buffer size.
132      *
133      * The trade-off of larger buffers is that more kernel memory
134      * is consumed.  YMMV, know your customers and your network!
135      *
136      * -John Heidemann <johnh@isi.edu> 25-Oct-96
137      *
138      * If no size is specified, use the kernel default.
139      */
140     if (send_buffer_size) {
141         stat = apr_setsocketopt(s, APR_SO_SNDBUF,  send_buffer_size);
142         if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) {
143             ap_log_error(APLOG_MARK, APLOG_WARNING, stat, NULL,
144                         "make_sock: failed to set SendBufferSize for %s, "
145                         "using default", addr);
146             /* not a fatal error */
147         }
148     }
149
150 #if DISABLE_NAGLE_INHERITED
151     ap_sock_disable_nagle(s);
152 #endif
153
154     if ((stat = apr_bind(s, localsa)) != APR_SUCCESS) {
155         ap_log_error(APLOG_MARK, APLOG_CRIT, stat, NULL,
156             "make_sock: could not bind to %s", addr);
157         apr_close_socket(s);
158         return stat;
159     }
160
161     if ((stat = apr_listen(s, ap_listenbacklog)) != APR_SUCCESS) {
162         ap_log_error(APLOG_MARK, APLOG_ERR, stat, NULL,
163             "make_sock: unable to listen for connections on %s", addr);
164         apr_close_socket(s);
165         return stat;
166     }
167
168     server->sd = s;
169     server->active = 1;
170     return APR_SUCCESS;
171 }
172
173
174 static apr_status_t close_listeners_on_exec(void *v)
175 {
176     ap_listen_rec *lr;
177
178     for (lr = ap_listeners; lr; lr = lr->next) {
179         apr_close_socket(lr->sd);
180         lr->active = 0;
181     }
182     return APR_SUCCESS;
183 }
184
185
186 static void alloc_listener(process_rec *process, char *addr, apr_port_t port)
187 {
188     ap_listen_rec **walk;
189     ap_listen_rec *new;
190     apr_status_t status;
191     char *oldaddr;
192     apr_port_t oldport;
193     apr_sockaddr_t *sa;
194
195     /* see if we've got an old listener for this address:port */
196     for (walk = &old_listeners; *walk; walk = &(*walk)->next) {
197         apr_get_sockaddr(&sa, APR_LOCAL, (*walk)->sd);
198         apr_get_port(&oldport, sa);
199         apr_get_ipaddr(&oldaddr, sa);
200         if (!strcmp(oldaddr, addr) && port == oldport) {
201             /* re-use existing record */
202             new = *walk;
203             *walk = new->next;
204             new->next = ap_listeners;
205             ap_listeners = new;
206             return;
207         }
208     }
209
210     /* this has to survive restarts */
211     new = apr_palloc(process->pool, sizeof(ap_listen_rec));
212     new->active = 0;
213     if ((status = apr_create_socket(&new->sd, APR_INET, SOCK_STREAM, 
214                                     process->pool)) != APR_SUCCESS) {
215         ap_log_error(APLOG_MARK, APLOG_CRIT, status, NULL,
216                  "make_sock: failed to get a socket for %s", addr);
217         return;
218     }
219     apr_get_sockaddr(&sa, APR_LOCAL, new->sd);
220     apr_set_port(sa, port);
221     apr_set_ipaddr(sa, addr);
222     new->next = ap_listeners;
223     ap_listeners = new;
224 }
225
226 #if !defined(WIN32) && !defined(SPMT_OS2_MPM)
227 static
228 #endif
229 int ap_listen_open(process_rec *process, apr_port_t port)
230 {
231     apr_pool_t *pconf = process->pconf;
232     ap_listen_rec *lr;
233     ap_listen_rec *next;
234     int num_open;
235
236     /* allocate a default listener if necessary */
237     if (ap_listeners == NULL) {
238         alloc_listener(process, APR_ANYADDR, port ? port : DEFAULT_HTTP_PORT);
239     }
240
241     num_open = 0;
242     for (lr = ap_listeners; lr; lr = lr->next) {
243         if (lr->active) {
244             ++num_open;
245         }
246         else {
247             if (make_sock(pconf, lr) == APR_SUCCESS) {
248                 ++num_open;
249                 lr->active = 1;
250             }
251         }
252     }
253
254     /* close the old listeners */
255     for (lr = old_listeners; lr; lr = next) {
256         apr_close_socket(lr->sd);
257         lr->active = 0;
258         next = lr->next;
259 /*      free(lr);*/
260     }
261     old_listeners = NULL;
262
263     apr_register_cleanup(pconf, NULL, apr_null_cleanup, close_listeners_on_exec);
264
265     return num_open ? 0 : -1;
266 }
267
268 #if !defined(WIN32)
269 int ap_setup_listeners(server_rec *s)
270 {
271     ap_listen_rec *lr;
272     int num_listeners = 0;
273     if (ap_listen_open(s->process, s->port)) {
274        return 0;
275     }
276     for (lr = ap_listeners; lr; lr = lr->next) {
277         num_listeners++;
278     }
279     return num_listeners;
280 }
281 #endif
282
283 void ap_listen_pre_config(void)
284 {
285     old_listeners = ap_listeners;
286     ap_listeners = NULL;
287     ap_listenbacklog = DEFAULT_LISTENBACKLOG;
288 }
289
290
291 const char *ap_set_listener(cmd_parms *cmd, void *dummy, const char *ips_)
292 {
293     char *ips=apr_pstrdup(cmd->pool, ips_);
294     char *ports;
295     unsigned short port;
296
297     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
298     if (err != NULL) {
299         return err;
300     }
301
302     ports = strchr(ips, ':');
303     if (ports != NULL) {
304         if (ports == ips) {
305             return "Missing IP address";
306         }
307         else if (ports[1] == '\0') {
308             return "Address must end in :<port-number>";
309         }
310         *(ports++) = '\0';
311     }
312     else {
313         ports = ips;
314     }
315
316     port = atoi(ports);
317     if (!port) {
318         return "Port must be numeric";
319     }
320
321     if (ports == ips) { /* no address */
322         alloc_listener(cmd->server->process, APR_ANYADDR, port);
323     }
324     else {
325         ips[(ports - ips) - 1] = '\0';
326         alloc_listener(cmd->server->process, ips, port);
327     }
328
329     return NULL;
330 }
331
332 const char *ap_set_listenbacklog(cmd_parms *cmd, void *dummy, const char *arg) 
333 {
334     int b;
335
336     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
337     if (err != NULL) {
338         return err;
339     }
340
341     b = atoi(arg);
342     if (b < 1) {
343         return "ListenBacklog must be > 0";
344     }
345     ap_listenbacklog = b;
346     return NULL;
347 }
348
349 const char *ap_set_send_buffer_size(cmd_parms *cmd, void *dummy, const char *arg)
350 {
351     int s = atoi(arg);
352     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
353     if (err != NULL) {
354         return err;
355     }
356
357     if (s < 512 && s != 0) {
358         return "SendBufferSize must be >= 512 bytes, or 0 for system default.";
359     }
360     send_buffer_size = s;
361     return NULL;
362 }