in src/pump.c [279:364]
apr_status_t serf_pump__write(serf_pump_t *pump,
bool fetch_new)
{
apr_status_t status = APR_SUCCESS;
apr_status_t read_status = APR_SUCCESS;
pump->hit_eof = FALSE;
while (status == APR_SUCCESS) {
/* First try to write out what is already stored in the
connection vecs. */
while (pump->vec_len && !status) {
status = socket_writev(pump);
/* If the write would have blocked, then we're done.
* Don't try to write anything else to the socket.
*/
if (APR_STATUS_IS_EPIPE(status)
|| APR_STATUS_IS_ECONNRESET(status)
|| APR_STATUS_IS_ECONNABORTED(status))
return no_more_writes(pump);
}
if (status || !fetch_new) {
/* If we couldn't write everything that we tried,
make sure that we will receive a write event next time */
if (APR_STATUS_IS_EAGAIN(status)
&& !pump->io->dirty_conn
&& !(pump->io->reqevents & APR_POLLOUT))
{
serf_io__set_pollset_dirty(pump->io);
}
return status;
}
else if (read_status || pump->vec_len || pump->hit_eof)
return read_status;
/* ### 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 ... */
pump->hit_eof = false;
read_status = serf_bucket_read_iovec(pump->ostream_head,
SERF_READ_ALL_AVAIL,
COUNT_OF(pump->vec),
pump->vec,
&pump->vec_len);
if (read_status == SERF_ERROR_WAIT_CONN) {
/* 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) */
serf__log(LOGLVL_INFO, LOGCOMP_CONN, __FILE__, pump->config,
"Output stream requested temporary write delay "
"on 0x%p\n", pump->io->u.v);
pump->stop_writing = true;
serf_io__set_pollset_dirty(pump->io);
read_status = APR_EAGAIN;
}
else if (APR_STATUS_IS_EAGAIN(read_status)) {
/* We read some stuff, but did we read everything ? */
if (pump->hit_eof)
read_status = APR_SUCCESS;
}
else if (SERF_BUCKET_READ_ERROR(read_status)) {
/* Something bad happened. Propagate any errors. */
return read_status;
}
}
return status;
}