From a2c7a1aafbd30c89e1c857ec8574080dcd83aa52 Mon Sep 17 00:00:00 2001
From: Valery Kharseko <vharseko@3a-systems.ru>
Date: Fri, 31 Jul 2026 17:01:00 +0000
Subject: [PATCH] [#794] Wait for the listen port to be open before returning from connection handler start (#796)

---
 opendj-server-legacy/src/main/java/org/opends/server/protocols/http/HTTPConnectionHandler.java |   42 +++++++++++++++++++++++++++++++-----------
 1 files changed, 31 insertions(+), 11 deletions(-)

diff --git a/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/HTTPConnectionHandler.java b/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/HTTPConnectionHandler.java
index af5b881..7f9cce5 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/HTTPConnectionHandler.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/HTTPConnectionHandler.java
@@ -167,8 +167,10 @@
   private final Object waitListen = new Object();
 
   /**
-   * The condition guarding {@link #waitListen}: set once the run method has tried to open the
-   * socket port, whether it succeeded or not. Guarded by {@link #waitListen}.
+   * Condition predicate for {@link #waitListen}: set once the handler thread
+   * has attempted to start the embedded HTTP server (successfully or not).
+   * Guarded by the {@link #waitListen} monitor; protects the start method
+   * against spurious wakeups.
    */
   private boolean listenAttempted;
 
@@ -574,6 +576,14 @@
     return httpServer != null;
   }
 
+  /**
+   * {@inheritDoc}
+   * <p>
+   * Deliberately left unsynchronized, unlike the overridden {@link Thread#start()}:
+   * the state this method touches is guarded by the {@link #waitListen} monitor, and
+   * holding the thread's own monitor across {@code waitListen.wait()} would block
+   * {@link Thread#join()}.
+   */
   @Override
   public void start()
   {
@@ -584,11 +594,19 @@
     {
       super.start();
 
+      final long deadlineNanos = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(LISTEN_TIMEOUT_MS);
       try
       {
         while (!listenAttempted)
         {
-          waitListen.wait();
+          final long remainingMs = TimeUnit.NANOSECONDS.toMillis(deadlineNanos - System.nanoTime());
+          if (remainingMs <= 0)
+          {
+            logger.error(ERR_CONNHANDLER_TIMEOUT_WAITING_FOR_LISTENER, handlerName,
+                TimeUnit.MILLISECONDS.toSeconds(LISTEN_TIMEOUT_MS));
+            break;
+          }
+          waitListen.wait(remainingMs);
         }
       }
       catch (InterruptedException e)
@@ -654,14 +672,6 @@
 
       try
       {
-        // At this point, the connection Handler either started correctly or failed
-        // to start but the start process should be notified and resume its work in any cases.
-        synchronized (waitListen)
-        {
-          listenAttempted = true;
-          waitListen.notifyAll();
-        }
-
         // If we have gotten here, then we are about to start listening
         // for the first time since startup or since we were previously disabled.
         // Start the embedded HTTP server
@@ -695,6 +705,16 @@
           lastIterationFailed = true;
         }
       }
+      finally
+      {
+        // At this point, the connection handler either started correctly or failed to start
+        // but the start process should be notified and resume its work in any cases.
+        synchronized (waitListen)
+        {
+          listenAttempted = true;
+          waitListen.notifyAll();
+        }
+      }
     }
 
     // Initiate shutdown

--
Gitblit v1.10.0