mpm_event: handle lingering close fully in process_lingering_close().
* server/mpm/event/event.c (start_lingering_close_blocking): Axe the function
and put the code directly in process_lingering_close() on the first call when
cs->pub.state == CONN_STATE_LINGER, this simplifies lingering close handling
from process_socket() and event_resume_suspended().
No functional changes.
Follow up to r1891716.
Github: #208
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1891717 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/server/mpm/event/event.c b/server/mpm/event/event.c
index 80fac98..b43b05e 100644
--- a/server/mpm/event/event.c
+++ b/server/mpm/event/event.c
@@ -829,48 +829,6 @@
ap_run_resume_connection(cs->c, cs->r);
}
-static void close_connection(event_conn_state_t *cs);
-
-/*
- * Close our side of the connection, flushing data to the client first.
- * Pre-condition: cs is not in any timeout queue and not in the pollset,
- * timeout_mutex is not locked
- * return: 0 if connection is fully closed,
- * 1 if connection is lingering
- * May only be called by worker thread.
- */
-static int start_lingering_close_blocking(event_conn_state_t *cs)
-{
- apr_socket_t *csd = cs->pfd.desc.s;
-
- /* defer_lingering_close() may have bumped lingering_count already */
- if (!cs->deferred_linger) {
- apr_atomic_inc32(&lingering_count);
- }
-
- apr_socket_timeout_set(csd, apr_time_from_sec(SECONDS_TO_LINGER));
- if (ap_start_lingering_close(cs->c)) {
- notify_suspend(cs);
- close_connection(cs);
- return DONE;
- }
-
- cs->queue_timestamp = apr_time_now();
- /*
- * If some module requested a shortened waiting period, only wait for
- * 2s (SECONDS_TO_LINGER). This is useful for mitigating certain
- * DoS attacks.
- */
- if (apr_table_get(cs->c->notes, "short-lingering-close")) {
- cs->pub.state = CONN_STATE_LINGER_SHORT;
- }
- else {
- cs->pub.state = CONN_STATE_LINGER_NORMAL;
- }
- notify_suspend(cs);
- return OK;
-}
-
/*
* Defer flush and close of the connection by adding it to defer_linger_chain,
* for a worker to grab it and do the job (should that be blocking).
@@ -1279,12 +1237,10 @@
return;
}
- if (cs->pub.state == CONN_STATE_LINGER) {
- rc = start_lingering_close_blocking(cs);
- }
- if (rc == OK && (cs->pub.state == CONN_STATE_LINGER_NORMAL ||
- cs->pub.state == CONN_STATE_LINGER_SHORT)) {
+ /* CONN_STATE_LINGER[_*] fall through process_lingering_close() */
+ if (cs->pub.state >= CONN_STATE_LINGER) {
process_lingering_close(cs);
+ return;
}
}
@@ -1304,14 +1260,7 @@
apr_atomic_dec32(&suspended_count);
c->suspended_baton = NULL;
- if (cs->pub.state == CONN_STATE_LINGER) {
- int rc = start_lingering_close_blocking(cs);
- if (rc == OK && (cs->pub.state == CONN_STATE_LINGER_NORMAL ||
- cs->pub.state == CONN_STATE_LINGER_SHORT)) {
- process_lingering_close(cs);
- }
- }
- else {
+ if (cs->pub.state < CONN_STATE_LINGER) {
cs->queue_timestamp = apr_time_now();
cs->pub.state = CONN_STATE_WRITE_COMPLETION;
notify_suspend(cs);
@@ -1322,6 +1271,10 @@
apr_pollset_add(event_pollset, &cs->pfd);
apr_thread_mutex_unlock(timeout_mutex);
}
+ else {
+ cs->pub.state = CONN_STATE_LINGER;
+ process_lingering_close(cs);
+ }
return OK;
}
@@ -1723,6 +1676,34 @@
"lingering close from state %i", (int)cs->pub.state);
AP_DEBUG_ASSERT(cs->pub.state >= CONN_STATE_LINGER);
+ if (cs->pub.state == CONN_STATE_LINGER) {
+ /* defer_lingering_close() may have bumped lingering_count already */
+ if (!cs->deferred_linger) {
+ apr_atomic_inc32(&lingering_count);
+ }
+
+ apr_socket_timeout_set(csd, apr_time_from_sec(SECONDS_TO_LINGER));
+ if (ap_start_lingering_close(cs->c)) {
+ notify_suspend(cs);
+ close_connection(cs);
+ return;
+ }
+
+ cs->queue_timestamp = apr_time_now();
+ /*
+ * If some module requested a shortened waiting period, only wait for
+ * 2s (SECONDS_TO_LINGER). This is useful for mitigating certain
+ * DoS attacks.
+ */
+ if (apr_table_get(cs->c->notes, "short-lingering-close")) {
+ cs->pub.state = CONN_STATE_LINGER_SHORT;
+ }
+ else {
+ cs->pub.state = CONN_STATE_LINGER_NORMAL;
+ }
+ notify_suspend(cs);
+ }
+
apr_socket_timeout_set(csd, 0);
do {
nbytes = sizeof(dummybuf);