code: private @Nullable IOException maybeReleaseConnection(@Nullable IOException e, boolean force) {
      Socket socket;
      Connection releasedConnection;
      boolean callEnd;
      synchronized (connectionPool) {
        if (force && exchange != null) {
          throw new IllegalStateException("cannot release connection while it is in use");
        }
        releasedConnection = this.connection;
        socket = this.connection != null && exchange == null && (force || noMoreExchanges)
            ? releaseConnectionNoEvents()
            : null;
        if (this.connection != null) releasedConnection = null;
        callEnd = noMoreExchanges && exchange == null;
      }
      closeQuietly(socket);
  
      if (releasedConnection != null) {
        eventListener.connectionReleased(call, releasedConnection);
      }
  
      if (callEnd) {
        boolean callFailed = (e != null);
        e = timeoutExit(e);
        if (callFailed) {
          eventListener.callFailed(call, e);
        } else {
          eventListener.callEnd(call);
        }
      }
      return e;
    }
docs: Release the connection if it is no longer needed. This is called after each exchange completes
  and after the call signals that no more exchanges are expected.
  
  <p>If the transmitter was canceled or timed out, this will wrap {@code e} in an exception that
  provides that additional context. Otherwise {@code e} is returned as-is.
  
  @param force true to release the connection even if more exchanges are expected for the call.