static int open_listeners(apr_pool_t *pool, apr_port_t port)
{
    ap_listen_rec *lr;
    ap_listen_rec *next;
    ap_listen_rec *previous;
    int num_open;
    const char *userdata_key = "ap_open_listeners";
    void *data;

    /* Don't allocate a default listener.  If we need to listen to a
     * port, then the user needs to have a Listen directive in their
     * config file.
     */
    num_open = 0;
    previous = NULL;
    for (lr = ap_listeners; lr; previous = lr, lr = lr->next) {
        if (lr->active) {
            ++num_open;
        }
        else {
#if APR_HAVE_IPV6
            int v6only_setting;
            /* If we are trying to bind to 0.0.0.0 and the previous listener
             * was :: on the same port and in turn that socket does not have
             * the IPV6_V6ONLY flag set; we must skip the current attempt to
             * listen (which would generate an error). IPv4 will be handled
             * on the established IPv6 socket.
             */
            if (previous != NULL &&
                lr->bind_addr->family == APR_INET &&
                lr->bind_addr->sa.sin.sin_addr.s_addr == INADDR_ANY &&
                lr->bind_addr->port == previous->bind_addr->port &&
                previous->bind_addr->family == APR_INET6 &&
                IN6_IS_ADDR_UNSPECIFIED(
                    &previous->bind_addr->sa.sin6.sin6_addr) &&
                apr_socket_opt_get(previous->sd, APR_IPV6_V6ONLY,
                                   &v6only_setting) == APR_SUCCESS &&
                v6only_setting == 0) {

                /* Remove the current listener from the list */
                previous->next = lr->next;
                continue;
            }
#endif
            if (make_sock(pool, lr) == APR_SUCCESS) {
                ++num_open;
                lr->active = 1;
            }
            else {
#if APR_HAVE_IPV6
                /* If we tried to bind to ::, and the next listener is
                 * on 0.0.0.0 with the same port, don't give a fatal
                 * error. The user will still get a warning from make_sock
                 * though.
                 */
                if (lr->next != NULL && lr->bind_addr->family == APR_INET6 &&
                    IN6_IS_ADDR_UNSPECIFIED(
                        &lr->bind_addr->sa.sin6.sin6_addr) &&
                    lr->bind_addr->port == lr->next->bind_addr->port &&
                    lr->next->bind_addr->family == APR_INET && 
                    lr->next->bind_addr->sa.sin.sin_addr.s_addr == INADDR_ANY) {

                    /* Remove the current listener from the list */
                    if (previous) {
                        previous->next = lr->next;
                    }
                    else {
                        ap_listeners = lr->next;
                    }

                    /* Although we've removed ourselves from the list,
                     * we need to make sure that the next iteration won't
                     * consider "previous" a working IPv6 '::' socket.
                     * Changing the family is enough to make sure the
                     * conditions before make_sock() fail.
                     */
                    lr->bind_addr->family = AF_INET;

                    continue;
                }
#endif
                /* fatal error */
                return -1;
            }
        }
    }

    /* close the old listeners */
    for (lr = old_listeners; lr; lr = next) {
        apr_socket_close(lr->sd);
        lr->active = 0;
        next = lr->next;
    }
    old_listeners = NULL;

#if AP_NONBLOCK_WHEN_MULTI_LISTEN
    /* if multiple listening sockets, make them non-blocking so that
     * if select()/poll() reports readability for a reset connection that
     * is already forgotten about by the time we call accept, we won't
     * be hung until another connection arrives on that port
     */
    if (ap_listeners && ap_listeners->next) {
        for (lr = ap_listeners; lr; lr = lr->next) {
            apr_status_t status;

            status = apr_socket_opt_set(lr->sd, APR_SO_NONBLOCK, 1);
            if (status != APR_SUCCESS) {
                ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_ERR, status, pool,
                              "unable to make listening socket non-blocking");
                return -1;
            }
        }
    }
#endif /* AP_NONBLOCK_WHEN_MULTI_LISTEN */

    /* we come through here on both passes of the open logs phase
     * only register the cleanup once... otherwise we try to close
     * listening sockets twice when cleaning up prior to exec
     */
    apr_pool_userdata_get(&data, userdata_key, pool);
    if (!data) {
        apr_pool_userdata_set((const void *)1, userdata_key,
                              apr_pool_cleanup_null, pool);
        apr_pool_cleanup_register(pool, NULL, apr_pool_cleanup_null,
                                  close_listeners_on_exec);
    }

    return num_open ? 0 : -1;
}