static apr_status_t socket_writev()

in modules/fcgid/fcgid_proc_unix.c [631:713]


static apr_status_t socket_writev(fcgid_ipc *ipc_handle,
                                  struct iovec *vec, int nvec,
                                  int *writecnt)
{
    apr_status_t rv;
    int retcode, unix_socket;
    fcgid_namedpipe_handle *handle_info;
    struct pollfd pollfds[1];

    handle_info = (fcgid_namedpipe_handle *) ipc_handle->ipc_handle_info;
    unix_socket = handle_info->handle_socket;

    /* Try nonblock write */
    do {
        if ((retcode = writev(unix_socket, vec, nvec)) > 0) {
            *writecnt = retcode;
            return APR_SUCCESS;
        }
    } while (retcode == -1 && APR_STATUS_IS_EINTR(errno));
    rv = errno;

    if (APR_STATUS_IS_EAGAIN(rv)) {
        /* poll() */
        pollfds[0].fd = unix_socket;
        pollfds[0].events = POLLOUT;
        do {
            retcode = poll(pollfds, 1, ipc_handle->communation_timeout * 1000);
        } while (retcode < 0 && APR_STATUS_IS_EINTR(errno));

        if (retcode < 0) {
            rv = errno;
        }
        else if (retcode == 0) {
            rv = APR_TIMEUP;
        }
        else {
            /* Write again */
            do {
                if ((retcode = writev(unix_socket, vec, nvec)) > 0) {
                    *writecnt = retcode;
                    return APR_SUCCESS;
                }
            } while (retcode == -1 && APR_STATUS_IS_EINTR(errno));
            rv = errno;
        }
    }

    if (APR_STATUS_IS_EAGAIN(rv)) {
        /* socket is writable, but we can't write the entire buffer; try to write a
         * smaller amount, and if even that fails then sleep
         */
        size_t to_write = vec[0].iov_len;
        int slept = 0;
        const apr_interval_time_t sleep_time = APR_USEC_PER_SEC / 4;
        const int max_sleeps = 8;

        do {
            if ((retcode = write(unix_socket, vec[0].iov_base, to_write)) > 0) {
                ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, ipc_handle->request,
                              "wrote %d byte(s) and slept %d time(s) after EAGAIN",
                              retcode, slept);
                *writecnt = retcode;
                return APR_SUCCESS;
            }
            if (APR_STATUS_IS_EAGAIN(errno)) {
                if (to_write == 1) {
                    apr_sleep(sleep_time);
                    ++slept;
                }
                else {
                    to_write /= 2;
                }
            }
        } while ((APR_STATUS_IS_EINTR(errno) || APR_STATUS_IS_EAGAIN(errno))
                 && slept < max_sleeps);
        rv = errno;
    }

    ap_log_rerror(APLOG_MARK, APLOG_INFO, rv,
                  ipc_handle->request,
                  "mod_fcgid: error writing data to FastCGI server");
    return rv;
}