private RealConnection findConnection(int connectTimeout, int readTimeout, int writeTimeout,
      int pingIntervalMillis, boolean connectionRetryEnabled) throws IOException {
    boolean foundPooledConnection = false;
    RealConnection result = null;
    Route selectedRoute = null;
    RealConnection releasedConnection;
    Socket toClose;
    synchronized (connectionPool) {
      if (transmitter.isCanceled()) throw new IOException("Canceled");
      hasStreamFailure = false; // This is a fresh attempt.

      Route previousRoute = retryCurrentRoute()
          ? transmitter.connection.route()
          : null;

      // Attempt to use an already-allocated connection. We need to be careful here because our
      // already-allocated connection may have been restricted from creating new exchanges.
      releasedConnection = transmitter.connection;
      toClose = transmitter.connection != null && transmitter.connection.noNewExchanges
          ? transmitter.releaseConnectionNoEvents()
          : null;

      if (transmitter.connection != null) {
        // We had an already-allocated connection and it's good.
        result = transmitter.connection;
        releasedConnection = null;
      }

      if (result == null) {
        // Attempt to get a connection from the pool.
        if (connectionPool.transmitterAcquirePooledConnection(address, transmitter, null, false)) {
          foundPooledConnection = true;
          result = transmitter.connection;
        } else {
          selectedRoute = previousRoute;
        }
      }
    }
    closeQuietly(toClose);

    if (releasedConnection != null) {
      eventListener.connectionReleased(call, releasedConnection);
    }
    if (foundPooledConnection) {
      eventListener.connectionAcquired(call, result);
    }
    if (result != null) {
      // If we found an already-allocated or pooled connection, we're done.
      return result;
    }

    // If we need a route selection, make one. This is a blocking operation.
    boolean newRouteSelection = false;
    if (selectedRoute == null && (routeSelection == null || !routeSelection.hasNext())) {
      newRouteSelection = true;
      routeSelection = routeSelector.next();
    }

    List<Route> routes = null;
    synchronized (connectionPool) {
      if (transmitter.isCanceled()) throw new IOException("Canceled");

      if (newRouteSelection) {
        // Now that we have a set of IP addresses, make another attempt at getting a connection from
        // the pool. This could match due to connection coalescing.
        routes = routeSelection.getAll();
        if (connectionPool.transmitterAcquirePooledConnection(
            address, transmitter, routes, false)) {
          foundPooledConnection = true;
          result = transmitter.connection;
        }
      }

      if (!foundPooledConnection) {
        if (selectedRoute == null) {
          selectedRoute = routeSelection.next();
        }

        // Create a connection and assign it to this allocation immediately. This makes it possible
        // for an asynchronous cancel() to interrupt the handshake we're about to do.
        result = new RealConnection(connectionPool, selectedRoute);
        connectingConnection = result;
      }
    }

    // If we found a pooled connection on the 2nd time around, we're done.
    if (foundPooledConnection) {
      eventListener.connectionAcquired(call, result);
      return result;
    }

    // Do TCP + TLS handshakes. This is a blocking operation.
    result.connect(connectTimeout, readTimeout, writeTimeout, pingIntervalMillis,
        connectionRetryEnabled, call, eventListener);
    connectionPool.getRouteDatabase().connected(result.route());

    Socket socket = null;
    synchronized (connectionPool) {
      connectingConnection = null;
      // Last attempt at connection coalescing, which only occurs if we attempted multiple
      // concurrent connections to the same host.
      if (connectionPool.transmitterAcquirePooledConnection(address, transmitter, routes, true)) {
        // We lost the race! Close the connection we created and return the pooled connection.
        result.noNewExchanges = true;
        socket = result.socket();
        result = transmitter.connection;
      } else {
        connectionPool.put(result);
        transmitter.acquireConnectionNoEvents(result);
      }
    }
    closeQuietly(socket);

    eventListener.connectionAcquired(call, result);
    return result;
  }
private RealConnection findConnection ( int connectTimeout , int readTimeout , int writeTimeout , int pingIntervalMillis , boolean connectionRetryEnabled ) throws IOException { boolean foundPooledConnection = false ; RealConnection result = null ; Route selectedRoute = null ; RealConnection releasedConnection ; Socket toClose ; synchronized ( connectionPool ) { if ( transmitter . isCanceled ( ) ) throw new IOException ( "Canceled" ) ; hasStreamFailure = false ; Route previousRoute = retryCurrentRoute ( ) ? transmitter . connection . route ( ) : null ; releasedConnection = transmitter . connection ; toClose = transmitter . connection != null && transmitter . connection . noNewExchanges ? transmitter . releaseConnectionNoEvents ( ) : null ; if ( transmitter . connection != null ) { result = transmitter . connection ; releasedConnection = null ; } if ( result == null ) { if ( connectionPool . transmitterAcquirePooledConnection ( address , transmitter , null , false ) ) { foundPooledConnection = true ; result = transmitter . connection ; } else { selectedRoute = previousRoute ; } } } closeQuietly ( toClose ) ; if ( releasedConnection != null ) { eventListener . connectionReleased ( call , releasedConnection ) ; } if ( foundPooledConnection ) { eventListener . connectionAcquired ( call , result ) ; } if ( result != null ) { return result ; } boolean newRouteSelection = false ; if ( selectedRoute == null && ( routeSelection == null || ! routeSelection . hasNext ( ) ) ) { newRouteSelection = true ; routeSelection = routeSelector . next ( ) ; } List < Route > routes = null ; synchronized ( connectionPool ) { if ( transmitter . isCanceled ( ) ) throw new IOException ( "Canceled" ) ; if ( newRouteSelection ) { routes = routeSelection . getAll ( ) ; if ( connectionPool . transmitterAcquirePooledConnection ( address , transmitter , routes , false ) ) { foundPooledConnection = true ; result = transmitter . connection ; } } if ( ! foundPooledConnection ) { if ( selectedRoute == null ) { selectedRoute = routeSelection . next ( ) ; } result = new RealConnection ( connectionPool , selectedRoute ) ; connectingConnection = result ; } } if ( foundPooledConnection ) { eventListener . connectionAcquired ( call , result ) ; return result ; } result . connect ( connectTimeout , readTimeout , writeTimeout , pingIntervalMillis , connectionRetryEnabled , call , eventListener ) ; connectionPool . getRouteDatabase ( ) . connected ( result . route ( ) ) ; Socket socket = null ; synchronized ( connectionPool ) { connectingConnection = null ; if ( connectionPool . transmitterAcquirePooledConnection ( address , transmitter , routes , true ) ) { result . noNewExchanges = true ; socket = result . socket ( ) ; result = transmitter . connection ; } else { connectionPool . put ( result ) ; transmitter . acquireConnectionNoEvents ( result ) ; } } closeQuietly ( socket ) ; eventListener . connectionAcquired ( call , result ) ; return result ; }
Returns a connection to host a new stream. This prefers the existing connection if it exists,
then the pool, finally building a new connection.