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