apr_status_t h2_mplx_out_read_to(h2_mplx *m, int stream_id, apr_bucket_brigade *bb, apr_off_t *plen, int *peos, apr_table_t **ptrailers) { apr_status_t status; int acquired; AP_DEBUG_ASSERT(m); if ((status = enter_mutex(m, &acquired)) == APR_SUCCESS) { h2_io *io = h2_io_set_get(m->stream_ios, stream_id); if (io && !io->orphaned) { H2_MPLX_IO_OUT(APLOG_TRACE2, m, io, "h2_mplx_out_read_to_pre"); status = h2_io_out_read_to(io, bb, plen, peos); H2_MPLX_IO_OUT(APLOG_TRACE2, m, io, "h2_mplx_out_read_to_post"); if (status == APR_SUCCESS) { h2_io_signal(io, H2_IO_WRITE); } } else { status = APR_ECONNABORTED; } *ptrailers = (*peos && io->response)? io->response->trailers : NULL; leave_mutex(m, acquired); } return status; }
apr_status_t h2_mplx_out_read_to(h2_mplx *m, int stream_id, apr_bucket_brigade *bb, apr_off_t *plen, int *peos, apr_table_t **ptrailers) { apr_status_t status; AP_DEBUG_ASSERT(m); if (m->aborted) { return APR_ECONNABORTED; } status = apr_thread_mutex_lock(m->lock); if (APR_SUCCESS == status) { h2_io *io = h2_io_set_get(m->stream_ios, stream_id); if (io && !io->orphaned) { H2_MPLX_IO_OUT(APLOG_TRACE2, m, io, "h2_mplx_out_read_to_pre"); status = h2_io_out_read_to(io, bb, plen, peos); H2_MPLX_IO_OUT(APLOG_TRACE2, m, io, "h2_mplx_out_read_to_post"); if (status == APR_SUCCESS && io->output_drained) { apr_thread_cond_signal(io->output_drained); } } else { status = APR_ECONNABORTED; } *ptrailers = (*peos && io->response)? io->response->trailers : NULL; apr_thread_mutex_unlock(m->lock); } return status; }
h2_stream *h2_mplx_next_submit(h2_mplx *m, h2_stream_set *streams) { apr_status_t status; h2_stream *stream = NULL; AP_DEBUG_ASSERT(m); if (m->aborted) { return NULL; } status = apr_thread_mutex_lock(m->lock); if (APR_SUCCESS == status) { h2_io *io = h2_io_set_pop_highest_prio(m->ready_ios); if (io) { stream = h2_stream_set_get(streams, io->id); if (stream) { if (io->rst_error) { h2_stream_rst(stream, io->rst_error); } else { AP_DEBUG_ASSERT(io->response); H2_MPLX_IO_OUT(APLOG_TRACE2, m, io, "h2_mplx_next_submit_pre"); h2_stream_set_response(stream, io->response, io->bbout); H2_MPLX_IO_OUT(APLOG_TRACE2, m, io, "h2_mplx_next_submit_post"); } } else { /* We have the io ready, but the stream has gone away, maybe * reset by the client. Should no longer happen since such * streams should clear io's from the ready queue. */ ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, m->c, APLOGNO(02953) "h2_mplx(%ld): stream for response %d closed, " "resetting io to close request processing", m->id, io->id); io->orphaned = 1; if (io->task_done) { io_destroy(m, io, 1); } else { /* hang around until the h2_task is done, but * shutdown input and send out any events (e.g. window * updates) asap. */ h2_io_in_shutdown(io); h2_io_rst(io, H2_ERR_STREAM_CLOSED); io_process_events(m, io); } } if (io->output_drained) { apr_thread_cond_signal(io->output_drained); } } apr_thread_mutex_unlock(m->lock); } return stream; }
h2_stream *h2_mplx_next_submit(h2_mplx *m, h2_stream_set *streams) { apr_status_t status; h2_stream *stream = NULL; int acquired; AP_DEBUG_ASSERT(m); if ((status = enter_mutex(m, &acquired)) == APR_SUCCESS) { h2_io *io = h2_io_set_pop_highest_prio(m->ready_ios); if (io && !m->aborted) { stream = h2_stream_set_get(streams, io->id); if (stream) { if (io->rst_error) { h2_stream_rst(stream, io->rst_error); } else { AP_DEBUG_ASSERT(io->response); H2_MPLX_IO_OUT(APLOG_TRACE2, m, io, "h2_mplx_next_submit_pre"); h2_stream_set_response(stream, io->response, io->bbout); H2_MPLX_IO_OUT(APLOG_TRACE2, m, io, "h2_mplx_next_submit_post"); } } else { /* We have the io ready, but the stream has gone away, maybe * reset by the client. Should no longer happen since such * streams should clear io's from the ready queue. */ ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, m->c, "h2_mplx(%ld): stream for response %d closed, " "resetting io to close request processing", m->id, io->id); h2_io_make_orphaned(io, H2_ERR_STREAM_CLOSED); if (!io->worker_started || io->worker_done) { io_destroy(m, io, 1); } else { /* hang around until the h2_task is done, but * shutdown input and send out any events (e.g. window * updates) asap. */ h2_io_in_shutdown(io); io_process_events(m, io); } } h2_io_signal(io, H2_IO_WRITE); } leave_mutex(m, acquired); } return stream; }
apr_status_t h2_mplx_out_rst(h2_mplx *m, int stream_id, int error) { apr_status_t status; int acquired; AP_DEBUG_ASSERT(m); if ((status = enter_mutex(m, &acquired)) == APR_SUCCESS) { h2_io *io = h2_io_set_get(m->stream_ios, stream_id); if (io && !io->rst_error && !io->orphaned) { h2_io_rst(io, error); if (!io->response) { h2_io_set_add(m->ready_ios, io); } H2_MPLX_IO_OUT(APLOG_TRACE2, m, io, "h2_mplx_out_rst"); have_out_data_for(m, stream_id); h2_io_signal(io, H2_IO_WRITE); } else { status = APR_ECONNABORTED; } leave_mutex(m, acquired); } return status; }
apr_status_t h2_mplx_out_write(h2_mplx *m, int stream_id, ap_filter_t* f, apr_bucket_brigade *bb, apr_table_t *trailers, struct apr_thread_cond_t *iowait) { apr_status_t status; int acquired; AP_DEBUG_ASSERT(m); if ((status = enter_mutex(m, &acquired)) == APR_SUCCESS) { h2_io *io = h2_io_set_get(m->stream_ios, stream_id); if (io && !io->orphaned) { status = out_write(m, io, f, bb, trailers, iowait); ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, m->c, "h2_mplx(%ld-%d): write with trailers=%s", m->id, io->id, trailers? "yes" : "no"); H2_MPLX_IO_OUT(APLOG_TRACE2, m, io, "h2_mplx_out_write"); have_out_data_for(m, stream_id); } else { status = APR_ECONNABORTED; } leave_mutex(m, acquired); } return status; }
apr_status_t h2_mplx_out_rst(h2_mplx *m, int stream_id, int error) { apr_status_t status; AP_DEBUG_ASSERT(m); if (m->aborted) { return APR_ECONNABORTED; } status = apr_thread_mutex_lock(m->lock); if (APR_SUCCESS == status) { if (!m->aborted) { h2_io *io = h2_io_set_get(m->stream_ios, stream_id); if (io && !io->rst_error && !io->orphaned) { h2_io_rst(io, error); if (!io->response) { h2_io_set_add(m->ready_ios, io); } H2_MPLX_IO_OUT(APLOG_TRACE2, m, io, "h2_mplx_out_rst"); have_out_data_for(m, stream_id); if (io->output_drained) { apr_thread_cond_signal(io->output_drained); } } else { status = APR_ECONNABORTED; } } apr_thread_mutex_unlock(m->lock); } return status; }
apr_status_t h2_mplx_out_close(h2_mplx *m, int stream_id, apr_table_t *trailers) { apr_status_t status; AP_DEBUG_ASSERT(m); if (m->aborted) { return APR_ECONNABORTED; } status = apr_thread_mutex_lock(m->lock); if (APR_SUCCESS == status) { if (!m->aborted) { h2_io *io = h2_io_set_get(m->stream_ios, stream_id); if (io && !io->orphaned) { if (!io->response && !io->rst_error) { /* In case a close comes before a response was created, * insert an error one so that our streams can properly * reset. */ h2_response *r = h2_response_die(stream_id, APR_EGENERAL, io->request, m->pool); status = out_open(m, stream_id, r, NULL, NULL, NULL); ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, m->c, "h2_mplx(%ld-%d): close, no response, no rst", m->id, io->id); } ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, m->c, "h2_mplx(%ld-%d): close with trailers=%s", m->id, io->id, trailers? "yes" : "no"); status = h2_io_out_close(io, trailers); H2_MPLX_IO_OUT(APLOG_TRACE2, m, io, "h2_mplx_out_close"); have_out_data_for(m, stream_id); if (m->aborted) { /* if we were the last output, the whole session might * have gone down in the meantime. */ return APR_SUCCESS; } } else { status = APR_ECONNABORTED; } } apr_thread_mutex_unlock(m->lock); } return status; }
apr_status_t h2_mplx_out_write(h2_mplx *m, int stream_id, ap_filter_t* f, apr_bucket_brigade *bb, apr_table_t *trailers, struct apr_thread_cond_t *iowait) { apr_status_t status; AP_DEBUG_ASSERT(m); if (m->aborted) { return APR_ECONNABORTED; } status = apr_thread_mutex_lock(m->lock); if (APR_SUCCESS == status) { if (!m->aborted) { h2_io *io = h2_io_set_get(m->stream_ios, stream_id); if (io && !io->orphaned) { status = out_write(m, io, f, bb, trailers, iowait); ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, m->c, "h2_mplx(%ld-%d): write with trailers=%s", m->id, io->id, trailers? "yes" : "no"); H2_MPLX_IO_OUT(APLOG_TRACE2, m, io, "h2_mplx_out_write"); have_out_data_for(m, stream_id); if (m->aborted) { return APR_ECONNABORTED; } } else { status = APR_ECONNABORTED; } } if (m->lock) { apr_thread_mutex_unlock(m->lock); } } return status; }
apr_status_t h2_mplx_out_close(h2_mplx *m, int stream_id, apr_table_t *trailers) { apr_status_t status; int acquired; AP_DEBUG_ASSERT(m); if ((status = enter_mutex(m, &acquired)) == APR_SUCCESS) { h2_io *io = h2_io_set_get(m->stream_ios, stream_id); if (io && !io->orphaned) { if (!io->response && !io->rst_error) { /* In case a close comes before a response was created, * insert an error one so that our streams can properly * reset. */ h2_response *r = h2_response_die(stream_id, APR_EGENERAL, io->request, m->pool); status = out_open(m, stream_id, r, NULL, NULL, NULL); ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, m->c, "h2_mplx(%ld-%d): close, no response, no rst", m->id, io->id); } ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, m->c, "h2_mplx(%ld-%d): close with trailers=%s", m->id, io->id, trailers? "yes" : "no"); status = h2_io_out_close(io, trailers); H2_MPLX_IO_OUT(APLOG_TRACE2, m, io, "h2_mplx_out_close"); have_out_data_for(m, stream_id); } else { status = APR_ECONNABORTED; } leave_mutex(m, acquired); } return status; }