PROXY_DECLARE(apr_status_t) ap_proxy_tunnel_create(proxy_tunnel_rec **ptunnel,
                                                   request_rec *r,
                                                   conn_rec *origin)
{
    apr_status_t rv;
    apr_pollfd_t *pfds;
    conn_rec *c = r->connection;
    proxy_tunnel_rec *tunnel;

    *ptunnel = NULL;

    tunnel = apr_pcalloc(r->pool, sizeof(*tunnel));

    tunnel->r = r;
    tunnel->origin = origin;
    tunnel->bb_i = apr_brigade_create(r->pool,
                                      c->bucket_alloc);
    tunnel->bb_o = apr_brigade_create(origin->pool,
                                      origin->bucket_alloc);
    
    tunnel->timeout = -1;
    rv = apr_pollset_create(&tunnel->pollset, 2, r->pool,
                            APR_POLLSET_NOCOPY);
    if (rv != APR_SUCCESS) {
        return rv;
    }

    tunnel->pfds = apr_array_make(r->pool, 2, sizeof(apr_pollfd_t));
    apr_array_push(tunnel->pfds); /* pfds[0] */
    apr_array_push(tunnel->pfds); /* pfds[1] */

    pfds = &APR_ARRAY_IDX(tunnel->pfds, 0, apr_pollfd_t);
    pfds[0].desc.s = ap_get_conn_socket(c);
    pfds[1].desc.s = ap_get_conn_socket(origin);
    pfds[0].desc_type = pfds[1].desc_type = APR_POLL_SOCKET;
    pfds[0].reqevents = pfds[1].reqevents = APR_POLLIN | APR_POLLHUP;
    pfds[0].p = pfds[1].p = r->pool;

    /* The input/output filter stacks should contain connection filters only */
    r->output_filters = c->output_filters;
    r->proto_output_filters = c->output_filters;
    r->input_filters = c->input_filters;
    r->proto_input_filters = c->input_filters;

    c->keepalive = AP_CONN_CLOSE;
    origin->keepalive = AP_CONN_CLOSE;

    *ptunnel = tunnel;
    return APR_SUCCESS;
}