static apr_status_t process_connection()

in src/outgoing.c [1063:1176]


static apr_status_t process_connection(serf_connection_t *conn,
                                       apr_int16_t events)
{
    apr_status_t status;
#ifdef SERF_DEBUG_BUCKET_USE
      serf_request_t *rq;
#endif

#ifdef SERF_DEBUG_BUCKET_USE
    serf_debug__entered_loop(conn->allocator);

    for (rq = conn->written_reqs; rq; rq = rq->next) {
          if (rq->allocator)
              serf_debug__entered_loop(rq->allocator);
    }

    for (rq = conn->done_reqs; rq; rq = rq->next) {
          if (rq->allocator)
              serf_debug__entered_loop(rq->allocator);
    }
#endif

    /* POLLHUP/ERR should come after POLLIN so if there's an error message or
     * the like sitting on the connection, we give the app a chance to read
     * it before we trigger a reset condition.
     */
    if ((events & APR_POLLIN) != 0
        && !conn->wait_for_connect) {

        /* If the stop_writing flag was set on the connection, reset it now
           because there is some data to read. */
        if (conn->pump.stop_writing) {
            conn->pump.stop_writing = false;
            serf_io__set_pollset_dirty(&conn->io);
        }

        if ((status = conn->perform_read(conn)) != APR_SUCCESS)
            return status;

        /* If we decided to reset our connection, return now as we don't
         * want to write.
         */
        if ((conn->seen_in_pollset & APR_POLLHUP) != 0) {
            return APR_SUCCESS;
        }
    }
    if ((events & APR_POLLHUP) != 0) {
        /* The connection got reset by the server. */
        return conn->perform_hangup(conn);
    }
    if ((events & APR_POLLERR) != 0) {
        /* We might be talking to a buggy HTTP server that doesn't
         * do lingering-close.  (httpd < 2.1.8 does this.)
         *
         * See:
         *
         * http://issues.apache.org/bugzilla/show_bug.cgi?id=35292
         */
        if (conn->completed_requests && !conn->probable_keepalive_limit) {
            return reset_connection(conn, 1);
        }
#ifdef SO_ERROR
        /* If possible, get the error from the platform's socket layer and
           convert it to an APR status code. */
        {
            apr_os_sock_t osskt;
            if (!apr_os_sock_get(&osskt, conn->skt)) {
                int error;
                apr_socklen_t l = sizeof(error);

                if (!getsockopt(osskt, SOL_SOCKET, SO_ERROR, (char*)&error,
                                &l)) {
                    status = APR_FROM_OS_ERROR(error);

                    /* Handle fallback for multi-homed servers.

                       ### Improve algorithm to find better than just 'next'?

                       Current Windows versions already handle re-ordering for
                       api users by using statistics on the recently failed
                       connections to order the list of addresses. */
                    if (conn->completed_requests == 0
                        && conn->address->next != NULL
                        && (APR_STATUS_IS_ECONNREFUSED(status)
                            || APR_STATUS_IS_TIMEUP(status)
                            || APR_STATUS_IS_ENETUNREACH(status))) {

                        conn->address = conn->address->next;
                        return reset_connection(conn, 1);
                    }

                    return status;
                  }
            }
        }
#endif
        return APR_EGENERAL;
    }
    if ((events & APR_POLLOUT) != 0) {
        if (conn->wait_for_connect) {
            conn->wait_for_connect = false;

            /* We are now connected. Socket is now usable */
            serf_io__set_pollset_dirty(&conn->io);

            if ((status = connect_connection(conn)) != APR_SUCCESS)
                return status;
        }

        if ((status = conn->perform_write(conn)) != APR_SUCCESS)
            return status;
    }
    return APR_SUCCESS;
}