public static InetAddress findConnectingAddress(
            InetSocketAddress targetAddress, long maxWaitMillis, long startLoggingAfter)
            throws IOException {
        if (targetAddress == null) {
            throw new NullPointerException("targetAddress must not be null");
        }
        if (maxWaitMillis <= 0) {
            throw new IllegalArgumentException("Max wait time must be positive");
        }

        final long startTimeNanos = System.nanoTime();

        long currentSleepTime = MIN_SLEEP_TIME;
        long elapsedTimeMillis = 0;

        final List<AddressDetectionState> strategies =
                Collections.unmodifiableList(
                        Arrays.asList(
                                AddressDetectionState.LOCAL_HOST,
                                AddressDetectionState.ADDRESS,
                                AddressDetectionState.FAST_CONNECT,
                                AddressDetectionState.SLOW_CONNECT));

        // loop while there is time left
        while (elapsedTimeMillis < maxWaitMillis) {
            boolean logging = elapsedTimeMillis >= startLoggingAfter;
            if (logging) {
                LOG.info("Trying to connect to " + targetAddress);
            }

            // Try each strategy in order
            for (AddressDetectionState strategy : strategies) {
                InetAddress address = findAddressUsingStrategy(strategy, targetAddress, logging);
                if (address != null) {
                    return address;
                }
            }

            // we have made a pass with all strategies over all interfaces
            // sleep for a while before we make the next pass
            elapsedTimeMillis = (System.nanoTime() - startTimeNanos) / 1_000_000;

            long toWait = Math.min(maxWaitMillis - elapsedTimeMillis, currentSleepTime);
            if (toWait > 0) {
                if (logging) {
                    LOG.info("Could not connect. Waiting for {} msecs before next attempt", toWait);
                } else {
                    LOG.debug(
                            "Could not connect. Waiting for {} msecs before next attempt", toWait);
                }

                try {
                    Thread.sleep(toWait);
                } catch (InterruptedException e) {
                    throw new IOException("Connection attempts have been interrupted.");
                }
            }

            // increase the exponential backoff timer
            currentSleepTime = Math.min(2 * currentSleepTime, MAX_SLEEP_TIME);
        }

        // our attempts timed out. use the heuristic fallback
        LOG.warn(
                "Could not connect to {}. Selecting a local address using heuristics.",
                targetAddress);
        InetAddress heuristic =
                findAddressUsingStrategy(AddressDetectionState.HEURISTIC, targetAddress, true);
        if (heuristic != null) {
            return heuristic;
        } else {
            LOG.warn(
                    "Could not find any IPv4 address that is not loopback or link-local. Using localhost address.");
            return InetAddress.getLocalHost();
        }
    }
@Test
    void testReturnLocalHostAddressUsingHeuristics() throws Exception {
        // instead of using a unstable localhost:port as "unreachable" to cause Test fails unstably
        // using a Absolutely unreachable outside ip:port
        InetSocketAddress unreachable = new InetSocketAddress("8.8.8.8", 0xFFFF);

        final long start = System.nanoTime();
        InetAddress add = ConnectionUtils.findConnectingAddress(unreachable, 2000, 400);

        // check that it did not take forever (max 30 seconds)
        // this check can unfortunately not be too tight, or it will be flaky on some CI
        // infrastructure
        assertThat(System.nanoTime() - start).isLessThan(30_000_000_000L);

        // we should have found a heuristic address
        assertThat(add).isNotNull();

        // make sure that we returned the InetAddress.getLocalHost as a heuristic
        assertThat(add).isEqualTo(InetAddress.getLocalHost());
    }