]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: listeners: make unbind_listener() converge if needed
authorWilly Tarreau <w@1wt.eu>
Wed, 23 Sep 2020 14:24:23 +0000 (16:24 +0200)
committerWilly Tarreau <w@1wt.eu>
Fri, 9 Oct 2020 09:27:29 +0000 (11:27 +0200)
The ZOMBIE state on listener is a real mess. Listeners passing through
this state have lost their consistency with the proxy AND with the fdtab.
Plus this state is not used for all foreign listeners, only for those
belonging to a proxy that entirely runs on another process, otherwise it
stays in INIT state, which makes the usefulness extremely questionable.
But the real issue is that it's impossible to untangle the receivers
from the proxy state as long as we have this because of deinit()...

So what we do here is to start by making unbind_listener() support being
called more than once. This will permit to call it again to really close
the FD and finish the operations if it's called with an FD that's in a
fake state (such as INIT but with a valid fd).

src/listener.c

index 4b21f67a40872a989db853df8a1b13c6bd9f8120..8f54ae206f8f456f5003a11a37c0bd384b124fc9 100644 (file)
@@ -478,7 +478,8 @@ void dequeue_proxy_listeners(struct proxy *px)
 }
 
 /* Must be called with the lock held. Depending on <do_close> value, it does
- * what unbind_listener or unbind_listener_no_close should do.
+ * what unbind_listener or unbind_listener_no_close should do. It can also
+ * close a zombie listener's FD when called in early states.
  */
 void do_unbind_listener(struct listener *listener, int do_close)
 {
@@ -490,11 +491,12 @@ void do_unbind_listener(struct listener *listener, int do_close)
        if (listener->state >= LI_PAUSED) {
                listener->state = LI_ASSIGNED;
                fd_stop_both(listener->rx.fd);
-               if (do_close) {
-                       fd_delete(listener->rx.fd);
-                       listener->rx.flags &= ~RX_F_BOUND;
-                       listener->rx.fd = -1;
-               }
+       }
+
+       if (do_close && listener->rx.fd != -1) {
+               fd_delete(listener->rx.fd);
+               listener->rx.flags &= ~RX_F_BOUND;
+               listener->rx.fd = -1;
        }
 }