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;
}