From bcad7e6319a00ea0278fcad8125ac7116d6c55a5 Mon Sep 17 00:00:00 2001 From: Aurelien DARRAGON Date: Wed, 15 Feb 2023 09:30:54 +0100 Subject: [PATCH] MINOR: listener: add relax_listener() function There is a need for a small difference between resuming and relaxing a listener. When resuming, we expect that the listener may completely resume, this includes unpausing or rebinding if required. Resuming a listener is a best-effort operation: no matter the current state, try our best to bring the listener up to the LI_READY state. There are some cases where we only want to "relax" listeners that were previously restricted using limit_listener() or listener_full() functions. Here we don't want to ressucitate listeners, we're simply interested in cancelling out the previous restriction. To this day, listener_resume() on a unbound listener is broken, that's why the need for this wasn't felt yet. But we're trying to restore historical listener_resume() behavior, so we better prepare for this by introducing an explicit relax_listener() function that only does what is expected in such cases. This commit depends on: - "MINOR: listener/api: add lli hint to listener functions" --- include/haproxy/listener.h | 12 ++++++++++++ src/listener.c | 27 +++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/include/haproxy/listener.h b/include/haproxy/listener.h index 2b6c3dc27..001737239 100644 --- a/include/haproxy/listener.h +++ b/include/haproxy/listener.h @@ -59,6 +59,18 @@ int pause_listener(struct listener *l, int lpx, int lli); */ int resume_listener(struct listener *l, int lpx, int lli); +/* Same as resume_listener(), but will only work to resume from + * LI_FULL or LI_LIMITED states because we try to relax listeners that + * were temporarily restricted and not to resume inactive listeners that + * may have been paused or completely stopped in the meantime. + * Returns positive value for success and 0 for failure. + * It will need to operate under the proxy's lock and the listener's lock. + * The caller is responsible for indicating in lpx, lli whether the respective + * locks are already held (non-zero) or not (zero) so that the function pick + * the missing ones, in this order. + */ +int relax_listener(struct listener *l, int lpx, int lli); + /* * This function completely stops a listener. It will need to operate under the * proxy's lock, the protocol's and the listener's lock. The caller is diff --git a/src/listener.c b/src/listener.c index 295672233..ce7410546 100644 --- a/src/listener.c +++ b/src/listener.c @@ -571,6 +571,33 @@ int resume_listener(struct listener *l, int lpx, int lli) return ret; } +/* Same as resume_listener(), but will only work to resume from + * LI_FULL or LI_LIMITED states because we try to relax listeners that + * were temporarily restricted and not to resume inactive listeners that + * may have been paused or completely stopped in the meantime. + * Returns positive value for success and 0 for failure. + * It will need to operate under the proxy's lock and the listener's lock. + * The caller is responsible for indicating in lpx, lli whether the respective + * locks are already held (non-zero) or not (zero) so that the function pick + * the missing ones, in this order. + */ +int relax_listener(struct listener *l, int lpx, int lli) +{ + int ret = 1; + + if (!lli) + HA_RWLOCK_WRLOCK(LISTENER_LOCK, &l->lock); + + if (l->state != LI_FULL && l->state != LI_LIMITED) + goto end; /* listener may be suspended or even stopped */ + ret = resume_listener(l, lpx, 1); + + end: + if (!lli) + HA_RWLOCK_WRUNLOCK(LISTENER_LOCK, &l->lock); + return ret; +} + /* Marks a ready listener as full so that the stream code tries to re-enable * it upon next close() using resume_listener(). */