]> granicus.if.org Git - apache/blob - server/listen.c
promote
[apache] / server / listen.c
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
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #include "apr_network_io.h"
18 #include "apr_strings.h"
19
20 #define APR_WANT_STRFUNC
21 #include "apr_want.h"
22
23 #include "ap_config.h"
24 #include "httpd.h"
25 #include "http_main.h"
26 #include "http_config.h"
27 #include "http_core.h"
28 #include "ap_listen.h"
29 #include "http_log.h"
30 #include "mpm_common.h"
31
32 #include <stdlib.h>
33 #if APR_HAVE_UNISTD_H
34 #include <unistd.h>
35 #endif
36
37 /* we know core's module_index is 0 */
38 #undef APLOG_MODULE_INDEX
39 #define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX
40
41 AP_DECLARE_DATA ap_listen_rec *ap_listeners = NULL;
42
43 /* Let ap_num_listen_buckets be global so that it can
44  * be printed by ap_log_mpm_common(), but keep the listeners
45  * buckets static since it is used only here to close them
46  * all (including duplicated) with ap_close_listeners().
47  */
48 AP_DECLARE_DATA int ap_num_listen_buckets;
49 static ap_listen_rec **ap_listen_buckets;
50
51 /* Determine once, at runtime, whether or not SO_REUSEPORT
52  * is usable on this platform, and hence whether or not
53  * listeners can be duplicated (if configured).
54  */
55 AP_DECLARE_DATA int ap_have_so_reuseport = -1;
56
57 static ap_listen_rec *old_listeners;
58 static int ap_listenbacklog;
59 static int ap_listencbratio;
60 static int send_buffer_size;
61 static int receive_buffer_size;
62
63 /* TODO: make_sock is just begging and screaming for APR abstraction */
64 static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server)
65 {
66     apr_socket_t *s = server->sd;
67     int one = 1;
68 #if APR_HAVE_IPV6
69 #ifdef AP_ENABLE_V4_MAPPED
70     int v6only_setting = 0;
71 #else
72     int v6only_setting = 1;
73 #endif
74 #endif
75     apr_status_t stat;
76
77 #ifndef WIN32
78     stat = apr_socket_opt_set(s, APR_SO_REUSEADDR, one);
79     if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) {
80         ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p, APLOGNO(00067)
81                       "make_sock: for address %pI, apr_socket_opt_set: (SO_REUSEADDR)",
82                       server->bind_addr);
83         apr_socket_close(s);
84         return stat;
85     }
86 #endif
87
88     stat = apr_socket_opt_set(s, APR_SO_KEEPALIVE, one);
89     if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) {
90         ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p, APLOGNO(00068)
91                       "make_sock: for address %pI, apr_socket_opt_set: (SO_KEEPALIVE)",
92                       server->bind_addr);
93         apr_socket_close(s);
94         return stat;
95     }
96
97 #if APR_HAVE_IPV6
98     if (server->bind_addr->family == APR_INET6) {
99         stat = apr_socket_opt_set(s, APR_IPV6_V6ONLY, v6only_setting);
100         if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) {
101             ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p, APLOGNO(00069)
102                           "make_sock: for address %pI, apr_socket_opt_set: "
103                           "(IPV6_V6ONLY)",
104                           server->bind_addr);
105             apr_socket_close(s);
106             return stat;
107         }
108     }
109 #endif
110
111     /*
112      * To send data over high bandwidth-delay connections at full
113      * speed we must force the TCP window to open wide enough to keep the
114      * pipe full.  The default window size on many systems
115      * is only 4kB.  Cross-country WAN connections of 100ms
116      * at 1Mb/s are not impossible for well connected sites.
117      * If we assume 100ms cross-country latency,
118      * a 4kB buffer limits throughput to 40kB/s.
119      *
120      * To avoid this problem I've added the SendBufferSize directive
121      * to allow the web master to configure send buffer size.
122      *
123      * The trade-off of larger buffers is that more kernel memory
124      * is consumed.  YMMV, know your customers and your network!
125      *
126      * -John Heidemann <johnh@isi.edu> 25-Oct-96
127      *
128      * If no size is specified, use the kernel default.
129      */
130     if (send_buffer_size) {
131         stat = apr_socket_opt_set(s, APR_SO_SNDBUF,  send_buffer_size);
132         if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) {
133             ap_log_perror(APLOG_MARK, APLOG_WARNING, stat, p, APLOGNO(00070)
134                           "make_sock: failed to set SendBufferSize for "
135                           "address %pI, using default",
136                           server->bind_addr);
137             /* not a fatal error */
138         }
139     }
140     if (receive_buffer_size) {
141         stat = apr_socket_opt_set(s, APR_SO_RCVBUF, receive_buffer_size);
142         if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) {
143             ap_log_perror(APLOG_MARK, APLOG_WARNING, stat, p, APLOGNO(00071)
144                           "make_sock: failed to set ReceiveBufferSize for "
145                           "address %pI, using default",
146                           server->bind_addr);
147             /* not a fatal error */
148         }
149     }
150
151 #if APR_TCP_NODELAY_INHERITED
152     ap_sock_disable_nagle(s);
153 #endif
154
155 #if defined(SO_REUSEPORT)
156     if (ap_have_so_reuseport) {
157         int thesock;
158         apr_os_sock_get(&thesock, s);
159         if (setsockopt(thesock, SOL_SOCKET, SO_REUSEPORT,
160                        (void *)&one, sizeof(int)) < 0) {
161             stat = apr_get_netos_error();
162             ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p, APLOGNO(02638)
163                           "make_sock: for address %pI, apr_socket_opt_set: "
164                           "(SO_REUSEPORT)",
165                           server->bind_addr);
166             apr_socket_close(s);
167             return stat;
168         }
169     }
170 #endif
171
172     if ((stat = apr_socket_bind(s, server->bind_addr)) != APR_SUCCESS) {
173         ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT, stat, p, APLOGNO(00072)
174                       "make_sock: could not bind to address %pI",
175                       server->bind_addr);
176         apr_socket_close(s);
177         return stat;
178     }
179
180     if ((stat = apr_socket_listen(s, ap_listenbacklog)) != APR_SUCCESS) {
181         ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_ERR, stat, p, APLOGNO(00073)
182                       "make_sock: unable to listen for connections "
183                       "on address %pI",
184                       server->bind_addr);
185         apr_socket_close(s);
186         return stat;
187     }
188
189 #ifdef WIN32
190     /* I seriously doubt that this would work on Unix; I have doubts that
191      * it entirely solves the problem on Win32.  However, since setting
192      * reuseaddr on the listener -prior- to binding the socket has allowed
193      * us to attach to the same port as an already running instance of
194      * Apache, or even another web server, we cannot identify that this
195      * port was exclusively granted to this instance of Apache.
196      *
197      * So set reuseaddr, but do not attempt to do so until we have the
198      * parent listeners successfully bound.
199      */
200     stat = apr_socket_opt_set(s, APR_SO_REUSEADDR, one);
201     if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) {
202         ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p, APLOGNO(00074)
203                     "make_sock: for address %pI, apr_socket_opt_set: (SO_REUSEADDR)",
204                      server->bind_addr);
205         apr_socket_close(s);
206         return stat;
207     }
208 #endif
209
210     server->sd = s;
211     server->active = 1;
212
213     server->accept_func = NULL;
214
215     return APR_SUCCESS;
216 }
217
218 static const char* find_accf_name(server_rec *s, const char *proto)
219 {
220     const char* accf;
221     core_server_config *conf = ap_get_core_module_config(s->module_config);
222     if (!proto) {
223         return NULL;
224     }
225
226     accf = apr_table_get(conf->accf_map, proto);
227
228     if (accf && !strcmp("none", accf)) {
229         return NULL;
230     }
231
232     return accf;
233 }
234
235 static void ap_apply_accept_filter(apr_pool_t *p, ap_listen_rec *lis,
236                                            server_rec *server)
237 {
238     apr_socket_t *s = lis->sd;
239     const char *accf;
240     apr_status_t rv;
241     const char *proto;
242
243     proto = lis->protocol;
244
245     if (!proto) {
246         proto = ap_get_server_protocol(server);
247     }
248
249
250     accf = find_accf_name(server, proto);
251
252     if (accf) {
253 #if APR_HAS_SO_ACCEPTFILTER
254         /* In APR 1.x, the 2nd and 3rd parameters are char * instead of 
255          * const char *, so make a copy of those args here.
256          */
257         rv = apr_socket_accept_filter(s, apr_pstrdup(p, accf),
258                                       apr_pstrdup(p, ""));
259         if (rv != APR_SUCCESS && !APR_STATUS_IS_ENOTIMPL(rv)) {
260             ap_log_perror(APLOG_MARK, APLOG_WARNING, rv, p, APLOGNO(00075)
261                           "Failed to enable the '%s' Accept Filter",
262                           accf);
263         }
264 #else
265         rv = apr_socket_opt_set(s, APR_TCP_DEFER_ACCEPT, 30);
266         if (rv != APR_SUCCESS && !APR_STATUS_IS_ENOTIMPL(rv)) {
267             ap_log_perror(APLOG_MARK, APLOG_WARNING, rv, p, APLOGNO(00076)
268                               "Failed to enable APR_TCP_DEFER_ACCEPT");
269         }
270 #endif
271     }
272 }
273
274 static apr_status_t close_listeners_on_exec(void *v)
275 {
276     ap_close_listeners();
277     return APR_SUCCESS;
278 }
279
280 static const char *alloc_listener(process_rec *process, char *addr,
281                                   apr_port_t port, const char* proto,
282                                   void *slave)
283 {
284     ap_listen_rec **walk, *last;
285     apr_status_t status;
286     apr_sockaddr_t *sa;
287     int found_listener = 0;
288
289     /* see if we've got an old listener for this address:port */
290     for (walk = &old_listeners; *walk;) {
291         sa = (*walk)->bind_addr;
292         /* Some listeners are not real so they will not have a bind_addr. */
293         if (sa) {
294             ap_listen_rec *new;
295             apr_port_t oldport;
296
297             oldport = sa->port;
298             /* If both ports are equivalent, then if their names are equivalent,
299              * then we will re-use the existing record.
300              */
301             if (port == oldport &&
302                 ((!addr && !sa->hostname) ||
303                  ((addr && sa->hostname) && !strcmp(sa->hostname, addr)))) {
304                 new = *walk;
305                 *walk = new->next;
306                 new->next = ap_listeners;
307                 ap_listeners = new;
308                 found_listener = 1;
309                 continue;
310             }
311         }
312
313         walk = &(*walk)->next;
314     }
315
316     if (found_listener) {
317         if (ap_listeners->slave != slave) {
318             return "Cannot define a slave on the same IP:port as a Listener";
319         }
320         return NULL;
321     }
322
323     if ((status = apr_sockaddr_info_get(&sa, addr, APR_UNSPEC, port, 0,
324                                         process->pool))
325         != APR_SUCCESS) {
326         ap_log_perror(APLOG_MARK, APLOG_CRIT, status, process->pool, APLOGNO(00077)
327                       "alloc_listener: failed to set up sockaddr for %s",
328                       addr);
329         return "Listen setup failed";
330     }
331
332     /* Initialize to our last configured ap_listener. */
333     last = ap_listeners;
334     while (last && last->next) {
335         last = last->next;
336     }
337
338     while (sa) {
339         ap_listen_rec *new;
340
341         /* this has to survive restarts */
342         new = apr_palloc(process->pool, sizeof(ap_listen_rec));
343         new->active = 0;
344         new->next = 0;
345         new->bind_addr = sa;
346         new->protocol = apr_pstrdup(process->pool, proto);
347
348         /* Go to the next sockaddr. */
349         sa = sa->next;
350
351         status = apr_socket_create(&new->sd, new->bind_addr->family,
352                                     SOCK_STREAM, 0, process->pool);
353
354 #if APR_HAVE_IPV6
355         /* What could happen is that we got an IPv6 address, but this system
356          * doesn't actually support IPv6.  Try the next address.
357          */
358         if (status != APR_SUCCESS && !addr &&
359             new->bind_addr->family == APR_INET6) {
360             continue;
361         }
362 #endif
363         if (status != APR_SUCCESS) {
364             ap_log_perror(APLOG_MARK, APLOG_CRIT, status, process->pool, APLOGNO(00078)
365                           "alloc_listener: failed to get a socket for %s",
366                           addr);
367             return "Listen setup failed";
368         }
369
370         /* We need to preserve the order returned by getaddrinfo() */
371         if (last == NULL) {
372             ap_listeners = last = new;
373         } else {
374             last->next = new;
375             last = new;
376         }
377         new->slave = slave;
378     }
379
380     return NULL;
381 }
382 /* Evaluates to true if the (apr_sockaddr_t *) addr argument is the
383  * IPv4 match-any-address, 0.0.0.0. */
384 #define IS_INADDR_ANY(addr) ((addr)->family == APR_INET \
385                              && (addr)->sa.sin.sin_addr.s_addr == INADDR_ANY)
386
387 /* Evaluates to true if the (apr_sockaddr_t *) addr argument is the
388  * IPv6 match-any-address, [::]. */
389 #define IS_IN6ADDR_ANY(addr) ((addr)->family == APR_INET6 \
390                               && IN6_IS_ADDR_UNSPECIFIED(&(addr)->sa.sin6.sin6_addr))
391
392 /**
393  * Create, open, listen, and bind all sockets.
394  * @param process The process record for the currently running server
395  * @return The number of open sockets
396  */
397 static int open_listeners(apr_pool_t *pool)
398 {
399     ap_listen_rec *lr;
400     ap_listen_rec *next;
401     ap_listen_rec *previous;
402     int num_open;
403     const char *userdata_key = "ap_open_listeners";
404     void *data;
405 #if AP_NONBLOCK_WHEN_MULTI_LISTEN
406     int use_nonblock;
407 #endif
408
409     /* Don't allocate a default listener.  If we need to listen to a
410      * port, then the user needs to have a Listen directive in their
411      * config file.
412      */
413     num_open = 0;
414     previous = NULL;
415     for (lr = ap_listeners; lr; previous = lr, lr = lr->next) {
416         if (lr->active) {
417             ++num_open;
418         }
419         else {
420 #if APR_HAVE_IPV6
421             ap_listen_rec *cur;
422             int v6only_setting;
423             int skip = 0;
424
425             /* If we have the unspecified IPv4 address (0.0.0.0) and
426              * the unspecified IPv6 address (::) is next, we need to
427              * swap the order of these in the list. We always try to
428              * bind to IPv6 first, then IPv4, since an IPv6 socket
429              * might be able to receive IPv4 packets if V6ONLY is not
430              * enabled, but never the other way around.
431              * Note: In some configurations, the unspecified IPv6 address
432              * could be even later in the list.  This logic only corrects
433              * the situation where it is next in the list, such as when
434              * apr_sockaddr_info_get() returns an IPv4 and an IPv6 address,
435              * in that order.
436              */
437             if (lr->next != NULL
438                 && IS_INADDR_ANY(lr->bind_addr)
439                 && lr->bind_addr->port == lr->next->bind_addr->port
440                 && IS_IN6ADDR_ANY(lr->next->bind_addr)) {
441                 /* Exchange lr and lr->next */
442                 next = lr->next;
443                 lr->next = next->next;
444                 next->next = lr;
445                 if (previous) {
446                     previous->next = next;
447                 }
448                 else {
449                     ap_listeners = next;
450                 }
451                 lr = next;
452             }
453
454             /* If we are trying to bind to 0.0.0.0 and a previous listener
455              * was :: on the same port and in turn that socket does not have
456              * the IPV6_V6ONLY flag set; we must skip the current attempt to
457              * listen (which would generate an error). IPv4 will be handled
458              * on the established IPv6 socket.
459              */
460             if (IS_INADDR_ANY(lr->bind_addr) && previous) {
461                 for (cur = ap_listeners; cur != lr; cur = cur->next) {
462                     if (lr->bind_addr->port == cur->bind_addr->port
463                         && IS_IN6ADDR_ANY(cur->bind_addr)
464                         && apr_socket_opt_get(cur->sd, APR_IPV6_V6ONLY,
465                                               &v6only_setting) == APR_SUCCESS
466                         && v6only_setting == 0) {
467
468                         /* Remove the current listener from the list */
469                         previous->next = lr->next;
470                         lr = previous; /* maintain current value of previous after
471                                         * post-loop expression is evaluated
472                                         */
473                         skip = 1;
474                         break;
475                     }
476                 }
477                 if (skip) {
478                     continue;
479                 }
480             }
481 #endif
482             if (make_sock(pool, lr) == APR_SUCCESS) {
483                 ++num_open;
484             }
485             else {
486 #if APR_HAVE_IPV6
487                 /* If we tried to bind to ::, and the next listener is
488                  * on 0.0.0.0 with the same port, don't give a fatal
489                  * error. The user will still get a warning from make_sock
490                  * though.
491                  */
492                 if (lr->next != NULL
493                     && IS_IN6ADDR_ANY(lr->bind_addr)
494                     && lr->bind_addr->port == lr->next->bind_addr->port
495                     && IS_INADDR_ANY(lr->next->bind_addr)) {
496
497                     /* Remove the current listener from the list */
498                     if (previous) {
499                         previous->next = lr->next;
500                     }
501                     else {
502                         ap_listeners = lr->next;
503                     }
504
505                     /* Although we've removed ourselves from the list,
506                      * we need to make sure that the next iteration won't
507                      * consider "previous" a working IPv6 '::' socket.
508                      * Changing the family is enough to make sure the
509                      * conditions before make_sock() fail.
510                      */
511                     lr->bind_addr->family = AF_INET;
512
513                     continue;
514                 }
515 #endif
516                 /* fatal error */
517                 return -1;
518             }
519         }
520     }
521
522     /* close the old listeners */
523     ap_close_listeners_ex(old_listeners);
524     old_listeners = NULL;
525
526 #if AP_NONBLOCK_WHEN_MULTI_LISTEN
527     /* if multiple listening sockets, make them non-blocking so that
528      * if select()/poll() reports readability for a reset connection that
529      * is already forgotten about by the time we call accept, we won't
530      * be hung until another connection arrives on that port
531      */
532     use_nonblock = (ap_listeners && ap_listeners->next);
533     for (lr = ap_listeners; lr; lr = lr->next) {
534         apr_status_t status;
535
536         status = apr_socket_opt_set(lr->sd, APR_SO_NONBLOCK, use_nonblock);
537         if (status != APR_SUCCESS) {
538             ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_ERR, status, pool, APLOGNO(00079)
539                           "unable to control socket non-blocking status");
540             return -1;
541         }
542     }
543 #endif /* AP_NONBLOCK_WHEN_MULTI_LISTEN */
544
545     /* we come through here on both passes of the open logs phase
546      * only register the cleanup once... otherwise we try to close
547      * listening sockets twice when cleaning up prior to exec
548      */
549     apr_pool_userdata_get(&data, userdata_key, pool);
550     if (!data) {
551         apr_pool_userdata_set((const void *)1, userdata_key,
552                               apr_pool_cleanup_null, pool);
553         apr_pool_cleanup_register(pool, NULL, apr_pool_cleanup_null,
554                                   close_listeners_on_exec);
555     }
556
557     return num_open ? 0 : -1;
558 }
559
560 AP_DECLARE(int) ap_setup_listeners(server_rec *s)
561 {
562     server_rec *ls;
563     server_addr_rec *addr;
564     ap_listen_rec *lr;
565     int num_listeners = 0;
566     const char* proto;
567     int found;
568
569     for (ls = s; ls; ls = ls->next) {
570         proto = ap_get_server_protocol(ls);
571         if (!proto) {
572             found = 0;
573             /* No protocol was set for this vhost,
574              * use the default for this listener.
575              */
576             for (addr = ls->addrs; addr && !found; addr = addr->next) {
577                 for (lr = ap_listeners; lr; lr = lr->next) {
578                     if (apr_sockaddr_equal(lr->bind_addr, addr->host_addr) &&
579                         lr->bind_addr->port == addr->host_port) {
580                         ap_set_server_protocol(ls, lr->protocol);
581                         found = 1;
582                         break;
583                     }
584                 }
585             }
586
587             if (!found) {
588                 /* TODO: set protocol defaults per-Port, eg 25=smtp */
589                 ap_set_server_protocol(ls, "http");
590             }
591         }
592     }
593
594     if (open_listeners(s->process->pool)) {
595         return 0;
596     }
597
598     for (lr = ap_listeners; lr; lr = lr->next) {
599         num_listeners++;
600         found = 0;
601         for (ls = s; ls && !found; ls = ls->next) {
602             for (addr = ls->addrs; addr && !found; addr = addr->next) {
603                 if (apr_sockaddr_equal(lr->bind_addr, addr->host_addr) &&
604                     lr->bind_addr->port == addr->host_port) {
605                     found = 1;
606                     ap_apply_accept_filter(s->process->pool, lr, ls);
607                 }
608             }
609         }
610
611         if (!found) {
612             ap_apply_accept_filter(s->process->pool, lr, s);
613         }
614     }
615
616     return num_listeners;
617 }
618
619 AP_DECLARE(apr_status_t) ap_duplicate_listeners(apr_pool_t *p, server_rec *s,
620                                                 ap_listen_rec ***buckets,
621                                                 int *num_buckets)
622 {
623     static int warn_once;
624     int i;
625     apr_status_t stat;
626     int use_nonblock = 0;
627     ap_listen_rec *lr;
628
629     if (*num_buckets < 1) {
630         *num_buckets = 1;
631         if (ap_listencbratio > 0) {
632 #ifdef _SC_NPROCESSORS_ONLN
633             if (ap_have_so_reuseport) {
634                 int num_online_cores = sysconf(_SC_NPROCESSORS_ONLN),
635                     val = num_online_cores / ap_listencbratio;
636                 if (val > 1) {
637                     *num_buckets = val;
638                 }
639                 ap_log_perror(APLOG_MARK, APLOG_INFO, 0, p, APLOGNO(02819)
640                               "Using %i listeners bucket(s) based on %i "
641                               "online CPU cores and a ratio of %i",
642                               *num_buckets, num_online_cores,
643                               ap_listencbratio);
644             }
645             else
646 #endif
647             if (!warn_once) {
648                 ap_log_perror(APLOG_MARK, APLOG_WARNING, 0, p, APLOGNO(02820)
649                               "ListenCoresBucketsRatio ignored without "
650                               "SO_REUSEPORT and _SC_NPROCESSORS_ONLN "
651                               "support: using a single listeners bucket");
652                 warn_once = 1;
653             }
654         }
655     }
656
657     *buckets = apr_pcalloc(p, *num_buckets * sizeof(ap_listen_rec *));
658     (*buckets)[0] = ap_listeners;
659
660     for (i = 1; i < *num_buckets; i++) {
661         ap_listen_rec *last = NULL;
662         lr = ap_listeners;
663         while (lr) {
664             ap_listen_rec *duplr;
665             char *hostname;
666             apr_port_t port;
667             apr_sockaddr_t *sa;
668             duplr = apr_palloc(p, sizeof(ap_listen_rec));
669             duplr->slave = NULL;
670             duplr->protocol = apr_pstrdup(p, lr->protocol);
671             hostname = apr_pstrdup(p, lr->bind_addr->hostname);
672             port = lr->bind_addr->port;
673             apr_sockaddr_info_get(&sa, hostname, APR_UNSPEC, port, 0, p);
674             duplr->bind_addr = sa;
675             duplr->next = NULL;
676             stat = apr_socket_create(&duplr->sd, duplr->bind_addr->family,
677                                      SOCK_STREAM, 0, p);
678             if (stat != APR_SUCCESS) {
679                 ap_log_perror(APLOG_MARK, APLOG_CRIT, 0, p, APLOGNO(02640)
680                             "ap_duplicate_listeners: for address %pI, "
681                             "cannot duplicate a new socket!",
682                             duplr->bind_addr);
683                 return stat;
684             }
685             make_sock(p, duplr);
686 #if AP_NONBLOCK_WHEN_MULTI_LISTEN
687             use_nonblock = (ap_listeners && ap_listeners->next);
688             stat = apr_socket_opt_set(duplr->sd, APR_SO_NONBLOCK, use_nonblock);
689             if (stat != APR_SUCCESS) {
690                 ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p, APLOGNO(02641)
691                               "unable to control socket non-blocking status");
692                 return stat;
693             }
694 #endif
695             ap_apply_accept_filter(p, duplr, s);
696
697             if (last == NULL) {
698                 (*buckets)[i] = last = duplr;
699             }
700             else {
701                 last->next = duplr;
702                 last = duplr;
703             }
704             lr = lr->next;
705         }
706     }
707
708     ap_listen_buckets = *buckets;
709     ap_num_listen_buckets = *num_buckets;
710     return APR_SUCCESS;
711 }
712
713 AP_DECLARE_NONSTD(void) ap_close_listeners(void)
714 {
715     int i;
716
717     ap_close_listeners_ex(ap_listeners);
718
719     /* Start from index 1 since either ap_duplicate_listeners()
720      * was called and ap_listen_buckets[0] == ap_listeners, or
721      * it wasn't and ap_num_listen_buckets == 0.
722      */
723     for (i = 1; i < ap_num_listen_buckets; i++) {
724         ap_close_listeners_ex(ap_listen_buckets[i]);
725     }
726 }
727
728 AP_DECLARE_NONSTD(void) ap_close_listeners_ex(ap_listen_rec *listeners)
729 {
730     ap_listen_rec *lr;
731     for (lr = listeners; lr; lr = lr->next) {
732         apr_socket_close(lr->sd);
733         lr->active = 0;
734     }
735 }
736
737 AP_DECLARE_NONSTD(int) ap_close_selected_listeners(ap_slave_t *slave)
738 {
739     ap_listen_rec *lr;
740     int n = 0;
741
742     for (lr = ap_listeners; lr; lr = lr->next) {
743         if (lr->slave != slave) {
744             apr_socket_close(lr->sd);
745             lr->active = 0;
746         }
747         else {
748             ++n;
749         }
750     }
751     return n;
752 }
753
754 AP_DECLARE(void) ap_listen_pre_config(void)
755 {
756     old_listeners = ap_listeners;
757     ap_listeners = NULL;
758     ap_listen_buckets = NULL;
759     ap_num_listen_buckets = 0;
760     ap_listenbacklog = DEFAULT_LISTENBACKLOG;
761     ap_listencbratio = 0;
762
763     /* Check once whether or not SO_REUSEPORT is supported. */
764     if (ap_have_so_reuseport < 0) {
765         /* This is limited to Linux with defined SO_REUSEPORT (ie. 3.9+) for
766          * now since the implementation evenly distributes connections across
767          * all the listening threads/processes.
768          *
769          * *BSDs have SO_REUSEPORT too but with a different semantic: the first
770          * wildcard address bound socket or the last non-wildcard address bound
771          * socket will receive connections (no evenness garantee); the rest of
772          * the sockets bound to the same port will not.
773          * This can't (always) work for httpd.
774          *
775          * TODO: latests DragonFlyBSD's SO_REUSEPORT (seems to?) have the same
776          * semantic as Linux, so we may need HAVE_SO_REUSEPORT available from
777          * configure.in some day.
778          */
779 #if defined(SO_REUSEPORT) && defined(__linux__)
780         apr_socket_t *sock;
781         if (apr_socket_create(&sock, APR_UNSPEC, SOCK_STREAM, 0,
782                               ap_pglobal) == APR_SUCCESS) {
783             int thesock, on = 1;
784             apr_os_sock_get(&thesock, sock);
785             ap_have_so_reuseport = (setsockopt(thesock, SOL_SOCKET,
786                                                SO_REUSEPORT, (void *)&on,
787                                                sizeof(int)) == 0);
788             apr_socket_close(sock);
789         }
790         else
791 #endif
792         ap_have_so_reuseport = 0;
793
794     }
795 }
796
797 AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy,
798                                                 int argc, char *const argv[])
799 {
800     char *host, *scope_id, *proto;
801     apr_port_t port;
802     apr_status_t rv;
803     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
804
805     if (err != NULL) {
806         return err;
807     }
808
809     if (argc < 1 || argc > 2) {
810         return "Listen requires 1 or 2 arguments.";
811     }
812
813     rv = apr_parse_addr_port(&host, &scope_id, &port, argv[0], cmd->pool);
814     if (rv != APR_SUCCESS) {
815         return "Invalid address or port";
816     }
817
818     if (host && !strcmp(host, "*")) {
819         host = NULL;
820     }
821
822     if (scope_id) {
823         /* XXX scope id support is useful with link-local IPv6 addresses */
824         return "Scope id is not supported";
825     }
826
827     if (!port) {
828         return "Port must be specified";
829     }
830
831     if (argc != 2) {
832         if (port == 443) {
833             proto = "https";
834         } else {
835             proto = "http";
836         }
837     }
838     else {
839         proto = apr_pstrdup(cmd->pool, argv[1]);
840         ap_str_tolower(proto);
841     }
842
843     return alloc_listener(cmd->server->process, host, port, proto, NULL);
844 }
845
846 AP_DECLARE_NONSTD(const char *) ap_set_listenbacklog(cmd_parms *cmd,
847                                                      void *dummy,
848                                                      const char *arg)
849 {
850     int b;
851     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
852
853     if (err != NULL) {
854         return err;
855     }
856
857     b = atoi(arg);
858     if (b < 1) {
859         return "ListenBacklog must be > 0";
860     }
861
862     ap_listenbacklog = b;
863     return NULL;
864 }
865
866 AP_DECLARE_NONSTD(const char *) ap_set_listencbratio(cmd_parms *cmd,
867                                                      void *dummy,
868                                                      const char *arg)
869 {
870     int b;
871     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
872
873     if (err != NULL) {
874         return err;
875     }
876
877     b = atoi(arg);
878     if (b < 1) {
879         return "ListenCoresBucketsRatio must be > 0";
880     }
881
882     ap_listencbratio = b;
883     return NULL;
884 }
885
886 AP_DECLARE_NONSTD(const char *) ap_set_send_buffer_size(cmd_parms *cmd,
887                                                         void *dummy,
888                                                         const char *arg)
889 {
890     int s = atoi(arg);
891     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
892
893     if (err != NULL) {
894         return err;
895     }
896
897     if (s < 512 && s != 0) {
898         return "SendBufferSize must be >= 512 bytes, or 0 for system default.";
899     }
900
901     send_buffer_size = s;
902     return NULL;
903 }
904
905 AP_DECLARE_NONSTD(const char *) ap_set_receive_buffer_size(cmd_parms *cmd,
906                                                            void *dummy,
907                                                            const char *arg)
908 {
909     int s = atoi(arg);
910     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
911
912     if (err != NULL) {
913         return err;
914     }
915
916     if (s < 512 && s != 0) {
917         return "ReceiveBufferSize must be >= 512 bytes, or 0 for system default.";
918     }
919
920     receive_buffer_size = s;
921     return NULL;
922 }