// non-javadoc, see interface ClientConnectionOperator
  public void updateSecureConnection(
      OperatedClientConnection conn, HttpHost target, HttpContext context, HttpParams params)
      throws IOException {

    if (conn == null) {
      throw new IllegalArgumentException("Connection must not be null.");
    }
    if (target == null) {
      throw new IllegalArgumentException("Target host must not be null.");
    }
    // @@@ is context allowed to be null?
    if (params == null) {
      throw new IllegalArgumentException("Parameters must not be null.");
    }
    if (!conn.isOpen()) {
      throw new IllegalArgumentException("Connection must be open.");
    }

    final Scheme schm = schemeRegistry.getScheme(target.getSchemeName());
    if (!(schm.getSocketFactory() instanceof LayeredSocketFactory)) {
      throw new IllegalArgumentException(
          "Target scheme (" + schm.getName() + ") must have layered socket factory.");
    }

    final LayeredSocketFactory lsf = (LayeredSocketFactory) schm.getSocketFactory();
    final Socket sock;
    try {
      sock =
          lsf.createSocket(
              conn.getSocket(), target.getHostName(), schm.resolvePort(target.getPort()), true);
    } catch (ConnectException ex) {
      throw new HttpHostConnectException(target, ex);
    }
    prepareSocket(sock, context, params);
    conn.update(sock, target, lsf.isSecure(sock), params);
    // @@@ error handling: close the layered socket in case of exception?

  } // updateSecureConnection
  // non-javadoc, see interface ClientConnectionOperator
  public void openConnection(
      OperatedClientConnection conn,
      HttpHost target,
      InetAddress local,
      HttpContext context,
      HttpParams params)
      throws IOException {

    if (conn == null) {
      throw new IllegalArgumentException("Connection must not be null.");
    }
    if (target == null) {
      throw new IllegalArgumentException("Target host must not be null.");
    }
    // local address may be null
    // @@@ is context allowed to be null?
    if (params == null) {
      throw new IllegalArgumentException("Parameters must not be null.");
    }
    if (conn.isOpen()) {
      throw new IllegalArgumentException("Connection must not be open.");
    }

    final Scheme schm = schemeRegistry.getScheme(target.getSchemeName());
    final SocketFactory sf = schm.getSocketFactory();
    final SocketFactory plain_sf;
    final LayeredSocketFactory layered_sf;
    if (sf instanceof LayeredSocketFactory) {
      plain_sf = staticPlainSocketFactory;
      layered_sf = (LayeredSocketFactory) sf;
    } else {
      plain_sf = sf;
      layered_sf = null;
    }
    InetAddress[] addresses = InetAddress.getAllByName(target.getHostName());

    for (int i = 0; i < addresses.length; ++i) {
      Socket sock = plain_sf.createSocket();
      conn.opening(sock, target);

      try {
        Socket connsock =
            plain_sf.connectSocket(
                sock,
                addresses[i].getHostAddress(),
                schm.resolvePort(target.getPort()),
                local,
                0,
                params);
        if (sock != connsock) {
          sock = connsock;
          conn.opening(sock, target);
        }
        /*
         * prepareSocket is called on the just connected
         * socket before the creation of the layered socket to
         * ensure that desired socket options such as
         * TCP_NODELAY, SO_RCVTIMEO, SO_LINGER will be set
         * before any I/O is performed on the socket. This
         * happens in the common case as
         * SSLSocketFactory.createSocket performs hostname
         * verification which requires that SSL handshaking be
         * performed.
         */
        prepareSocket(sock, context, params);
        if (layered_sf != null) {
          Socket layeredsock =
              layered_sf.createSocket(
                  sock, target.getHostName(), schm.resolvePort(target.getPort()), true);
          if (layeredsock != sock) {
            conn.opening(layeredsock, target);
          }
          conn.openCompleted(sf.isSecure(layeredsock), params);
        } else {
          conn.openCompleted(sf.isSecure(sock), params);
        }
        break;
        // BEGIN android-changed
        //       catch SocketException to cover any kind of connect failure
      } catch (SocketException ex) {
        if (i == addresses.length - 1) {
          ConnectException cause =
              ex instanceof ConnectException
                  ? (ConnectException) ex
                  : new ConnectException(ex.getMessage(), ex);
          throw new HttpHostConnectException(target, cause);
        }
        // END android-changed
      } catch (ConnectTimeoutException ex) {
        if (i == addresses.length - 1) {
          throw ex;
        }
      }
    }
  } // openConnection