NOEXPORT OCSP_RESPONSE *ocsp_get_response(CLI *c,
        OCSP_REQUEST *req, char *url) {
    BIO *bio=NULL;
    OCSP_REQ_CTX *req_ctx=NULL;
    OCSP_RESPONSE *resp=NULL;
    char *host=NULL, *port=NULL, *path=NULL;
    SOCKADDR_UNION addr;
    int ssl;

    /* parse the OCSP URL */
    if(!OCSP_parse_url(url, &host, &port, &path, &ssl)) {
        s_log(LOG_ERR, "OCSP: Failed to parse the OCSP URL");
        goto cleanup;
    }
    if(ssl) {
        s_log(LOG_ERR, "OCSP: TLS not supported for OCSP"
            " - an additional stunnel service needs to be defined");
        goto cleanup;
    }
    if(!hostport2addr(&addr, host, port, 0)) {
        s_log(LOG_ERR, "OCSP: Failed to resolve the OCSP responder address");
        goto cleanup;
    }

    /* connect specified OCSP responder */
    c->fd=s_socket(addr.sa.sa_family, SOCK_STREAM, 0, 1, "OCSP: socket");
    if(c->fd==INVALID_SOCKET)
        goto cleanup;
    if(s_connect(c, &addr, addr_len(&addr)))
        goto cleanup;
    bio=BIO_new_socket((int)c->fd, BIO_NOCLOSE);
    if(!bio) {
        sslerror("OCSP: BIO_new_socket");
        goto cleanup;
    }
    s_log(LOG_DEBUG, "OCSP: Connected %s:%s", host, port);

    /* initialize an HTTP request with the POST method */
#if OPENSSL_VERSION_NUMBER>=0x10000000L
    req_ctx=OCSP_sendreq_new(bio, path, NULL, -1);
#else
    /* there is no way to send the Host header with older OpenSSL versions */
    req_ctx=OCSP_sendreq_new(bio, path, req, -1);
#endif
    if(!req_ctx) {
        sslerror("OCSP: OCSP_sendreq_new");
        goto cleanup;
    }
#if OPENSSL_VERSION_NUMBER>=0x10000000L
    /* add the HTTP headers */
    if(!OCSP_REQ_CTX_add1_header(req_ctx, "Host", host)) {
        sslerror("OCSP: OCSP_REQ_CTX_add1_header");
        goto cleanup;
    }
    if(!OCSP_REQ_CTX_add1_header(req_ctx, "User-Agent", "stunnel")) {
        sslerror("OCSP: OCSP_REQ_CTX_add1_header");
        goto cleanup;
    }
    /* add the remaining HTTP headers and the OCSP request body */
    if(!OCSP_REQ_CTX_set1_req(req_ctx, req)) {
        sslerror("OCSP: OCSP_REQ_CTX_set1_req");
        goto cleanup;
    }
#endif

    /* OCSP protocol communication loop */
    while(OCSP_sendreq_nbio(&resp, req_ctx)==-1) {
        s_poll_init(c->fds, 0);
        s_poll_add(c->fds, c->fd, BIO_should_read(bio), BIO_should_write(bio));
        switch(s_poll_wait(c->fds, c->opt->timeout_busy, 0)) {
        case -1:
            sockerror("OCSP: s_poll_wait");
            goto cleanup;
        case 0:
            s_log(LOG_INFO, "OCSP: s_poll_wait: TIMEOUTbusy exceeded");
            goto cleanup;
        }
    }
#if 0
    s_log(LOG_DEBUG, "OCSP: context state: 0x%x", *(int *)req_ctx);
#endif
    /* http://www.mail-archive.com/openssl-users@openssl.org/msg61691.html */
    if(resp) {
        s_log(LOG_DEBUG, "OCSP: Response received");
    } else {
        if(ERR_peek_error())
            sslerror("OCSP: OCSP_sendreq_nbio");
        else /* OpenSSL error: OCSP_sendreq_nbio does not use OCSPerr */
            s_log(LOG_ERR, "OCSP: OCSP_sendreq_nbio: OpenSSL internal error");
    }

cleanup:
    if(req_ctx)
        OCSP_REQ_CTX_free(req_ctx);
    if(bio)
        BIO_free_all(bio);
    if(c->fd!=INVALID_SOCKET) {
        closesocket(c->fd);
        c->fd=INVALID_SOCKET; /* avoid double close on cleanup */
    }
    if(host)
        OPENSSL_free(host);
    if(port)
        OPENSSL_free(port);
    if(path)
        OPENSSL_free(path);
    return resp;
}