FreeBSD/contrib/serf/outgoing.c
/* write data out to the connection */
write data out to the connection
write data out to the connection
static apr_status_t write_to_connection(serf_connection_t *conn)
{
    if (conn->probable_keepalive_limit &&
        conn->completed_requests > conn->probable_keepalive_limit) {
        conn->dirty_conn = 1;
        conn->ctx->dirty_pollset = 1;
        return APR_SUCCESS;
    }
    while (1) {
        serf_request_t *request;
        int stop_reading = 0;
        apr_status_t status;
        apr_status_t read_status;
        serf_bucket_t *ostreamt;
        serf_bucket_t *ostreamh;
        int max_outstanding_requests = conn->max_outstanding_requests;
        if (conn->state != SERF_CONN_CONNECTED)
            max_outstanding_requests = 1;
        if (max_outstanding_requests &&
            conn->completed_requests -
                conn->completed_responses >= max_outstanding_requests) {
            return APR_SUCCESS;
        }
        while (conn->vec_len) {
            status = socket_writev(conn);
            if (APR_STATUS_IS_EAGAIN(status))
                return APR_SUCCESS;
            if (APR_STATUS_IS_EPIPE(status) ||
                APR_STATUS_IS_ECONNRESET(status) ||
                APR_STATUS_IS_ECONNABORTED(status))
                return no_more_writes(conn);
            if (status)
                return status;
        }
        if (!request_or_data_pending(&request, conn)) {
            conn->dirty_conn = 1;
            conn->ctx->dirty_pollset = 1;
            return APR_SUCCESS;
        }
        status = prepare_conn_streams(conn, &conn->stream, &ostreamt, &ostreamh);
        if (status) {
            return status;
        }
        if (request) {
            if (request->req_bkt == NULL) {
                read_status = setup_request(request);
                if (read_status) {
                    return read_status;
                }
            }
            if (!request->writing_started) {
                request->writing_started = 1;
                serf_bucket_aggregate_append(ostreamt, request->req_bkt);
            }
        }
        read_status = serf_bucket_read_iovec(ostreamh,
                                             SERF_READ_ALL_AVAIL,
                                             IOV_MAX,
                                             conn->vec,
                                             &conn->vec_len);
        if (!conn->hit_eof) {
            if (APR_STATUS_IS_EAGAIN(read_status)) {
                stop_reading = 1;
            }
            else if (read_status == SERF_ERROR_WAIT_CONN) {
                conn->stop_writing = 1;
                conn->dirty_conn = 1;
                conn->ctx->dirty_pollset = 1;
            }
            else if (read_status && !APR_STATUS_IS_EOF(read_status)) {
                return read_status;
            }
        }
        if (conn->vec_len > 0) {
            status = socket_writev(conn);
            if (APR_STATUS_IS_EAGAIN(status))
                return APR_SUCCESS;
            if (APR_STATUS_IS_EPIPE(status))
                return no_more_writes(conn);
            if (APR_STATUS_IS_ECONNRESET(status) ||
                APR_STATUS_IS_ECONNABORTED(status)) {
                return no_more_writes(conn);
            }
            if (status)
                return status;
        }
        if (read_status == SERF_ERROR_WAIT_CONN) {
            stop_reading = 1;
            conn->stop_writing = 1;
            conn->dirty_conn = 1;
            conn->ctx->dirty_pollset = 1;
        }
        else if (request && read_status && conn->hit_eof &&
                 conn->vec_len == 0) {
            conn->hit_eof = 0;
            serf_bucket_destroy(request->req_bkt);
            request->req_bkt = NULL;
            if (conn->async_responses) {
                conn->requests = request->next;
                destroy_request(request);
            }
            conn->completed_requests++;
            if (conn->probable_keepalive_limit &&
                conn->completed_requests > conn->probable_keepalive_limit) {
                stop_reading = 1;
            }
        }
        if (stop_reading) {
            return APR_SUCCESS;
        }
    }
}
static apr_status_t write_to_connection ( serf_connection_t * conn ) { if ( conn -> probable_keepalive_limit && conn -> completed_requests > conn -> probable_keepalive_limit ) { conn -> dirty_conn = 1 ; conn -> ctx -> dirty_pollset = 1 ; return APR_SUCCESS ; } while ( 1 ) { serf_request_t * request ; int stop_reading = 0 ; apr_status_t status ; apr_status_t read_status ; serf_bucket_t * ostreamt ; serf_bucket_t * ostreamh ; int max_outstanding_requests = conn -> max_outstanding_requests ; if ( conn -> state != SERF_CONN_CONNECTED ) max_outstanding_requests = 1 ; if ( max_outstanding_requests && conn -> completed_requests - conn -> completed_responses >= max_outstanding_requests ) { return APR_SUCCESS ; } while ( conn -> vec_len ) { status = socket_writev ( conn ) ; if ( APR_STATUS_IS_EAGAIN ( status ) ) return APR_SUCCESS ; if ( APR_STATUS_IS_EPIPE ( status ) || APR_STATUS_IS_ECONNRESET ( status ) || APR_STATUS_IS_ECONNABORTED ( status ) ) return no_more_writes ( conn ) ; if ( status ) return status ; } if ( ! request_or_data_pending ( & request , conn ) ) { conn -> dirty_conn = 1 ; conn -> ctx -> dirty_pollset = 1 ; return APR_SUCCESS ; } status = prepare_conn_streams ( conn , & conn -> stream , & ostreamt , & ostreamh ) ; if ( status ) { return status ; } if ( request ) { if ( request -> req_bkt == NULL ) { read_status = setup_request ( request ) ; if ( read_status ) { return read_status ; } } if ( ! request -> writing_started ) { request -> writing_started = 1 ; serf_bucket_aggregate_append ( ostreamt , request -> req_bkt ) ; } } read_status = serf_bucket_read_iovec ( ostreamh , SERF_READ_ALL_AVAIL , IOV_MAX , conn -> vec , & conn -> vec_len ) ; if ( ! conn -> hit_eof ) { if ( APR_STATUS_IS_EAGAIN ( read_status ) ) { stop_reading = 1 ; } else if ( read_status == SERF_ERROR_WAIT_CONN ) { conn -> stop_writing = 1 ; conn -> dirty_conn = 1 ; conn -> ctx -> dirty_pollset = 1 ; } else if ( read_status && ! APR_STATUS_IS_EOF ( read_status ) ) { return read_status ; } } if ( conn -> vec_len > 0 ) { status = socket_writev ( conn ) ; if ( APR_STATUS_IS_EAGAIN ( status ) ) return APR_SUCCESS ; if ( APR_STATUS_IS_EPIPE ( status ) ) return no_more_writes ( conn ) ; if ( APR_STATUS_IS_ECONNRESET ( status ) || APR_STATUS_IS_ECONNABORTED ( status ) ) { return no_more_writes ( conn ) ; } if ( status ) return status ; } if ( read_status == SERF_ERROR_WAIT_CONN ) { stop_reading = 1 ; conn -> stop_writing = 1 ; conn -> dirty_conn = 1 ; conn -> ctx -> dirty_pollset = 1 ; } else if ( request && read_status && conn -> hit_eof && conn -> vec_len == 0 ) { conn -> hit_eof = 0 ; serf_bucket_destroy ( request -> req_bkt ) ; request -> req_bkt = NULL ; if ( conn -> async_responses ) { conn -> requests = request -> next ; destroy_request ( request ) ; } conn -> completed_requests ++ ; if ( conn -> probable_keepalive_limit && conn -> completed_requests > conn -> probable_keepalive_limit ) { stop_reading = 1 ; } } if ( stop_reading ) { return APR_SUCCESS ; } } }
write data out to the connection
write data out to the connection
/* backoff for now. */ /* Keep reading and sending until we run out of stuff to read, or
     * writing would block.
     */ /* If we're setting up an ssl tunnel, we can't send real requests
           at yet, as they need to be encrypted and our encrypt buckets
           aren't created yet as we still need to read the unencrypted
           response of the CONNECT request. */ /* backoff for now. */ /* If we have unwritten data, then write what we can. */ /* If the write would have blocked, then we're done. Don't try
             * to write anything else to the socket.
             */ /* ### can we have a short write, yet no EAGAIN? a short write
           ### would imply unwritten_len > 0 ... */ /* assert: unwritten_len == 0. */ /* We may need to move forward to a request which has something
         * to write.
         */ /* No more requests (with data) are registered with the
             * connection, and no data is pending on the outgoing stream.
             * Let's update the pollset so that we don't try to write to this
             * socket again.
             */ /* Something bad happened. Propagate any errors. */ /* ### optimize at some point by using read_for_sendfile */ /* TODO: now that read_iovec will effectively try to return as much
           data as available, we probably don't want to read ALL_AVAIL, but
           a lower number, like the size of one or a few TCP packets, the
           available TCP buffer size ... */ /* We read some stuff, but should not try to read again. */ /* The bucket told us that it can't provide more data until
                   more data is read from the socket. This normally happens
                   during a SSL handshake.

                   We should avoid looking for writability for a while so
                   that (hopefully) something will appear in the bucket so
                   we can actually write something. otherwise, we could
                   end up in a CPU spin: socket wants something, but we
                   don't have anything (and keep returning EAGAIN)
                 */ /* Something bad happened. Propagate any errors. */ /* If we got some data, then deliver it. */ /* ### what to do if we got no data?? is that a problem? */ /* If we can't write any more, or an error occurred, then
             * we're done here.
             */ /* If we hit the end of the request bucket and all of its data has
             * been written, then clear it out to signify that we're done
             * sending the request. On the next iteration through this loop:
             * - if there are remaining bytes they will be written, and as the 
             * request bucket will be completely read it will be destroyed then.
             * - we'll see if there are other requests that need to be sent 
             * ("pipelining").
             */ /* If our connection has async responses enabled, we're not
             * going to get a reply back, so kill the request.
             */ /* backoff for now. */ /* NOTREACHED */