private PGStream enableSSL(PGStream pgStream, boolean requireSSL, Properties info, Logger logger)
      throws IOException, SQLException {
    if (logger.logDebug()) logger.debug(" FE=> SSLRequest");

    // Send SSL request packet
    pgStream.SendInteger4(8);
    pgStream.SendInteger2(1234);
    pgStream.SendInteger2(5679);
    pgStream.flush();

    // Now get the response from the backend, one of N, E, S.
    int beresp = pgStream.ReceiveChar();
    switch (beresp) {
      case 'E':
        if (logger.logDebug()) logger.debug(" <=BE SSLError");

        // Server doesn't even know about the SSL handshake protocol
        if (requireSSL)
          throw new PSQLException(
              GT.tr("The server does not support SSL."), PSQLState.CONNECTION_FAILURE);

        // We have to reconnect to continue.
        pgStream.close();
        return new PGStream(pgStream.getHost(), pgStream.getPort());

      case 'N':
        if (logger.logDebug()) logger.debug(" <=BE SSLRefused");

        // Server does not support ssl
        if (requireSSL)
          throw new PSQLException(
              GT.tr("The server does not support SSL."), PSQLState.CONNECTION_FAILURE);

        return pgStream;

      case 'S':
        if (logger.logDebug()) logger.debug(" <=BE SSLOk");

        // Server supports ssl
        Driver.makeSSL(pgStream, info, logger);
        return pgStream;

      default:
        throw new PSQLException(
            GT.tr("An error occured while setting up the SSL connection."),
            PSQLState.CONNECTION_FAILURE);
    }
  }
  public ProtocolConnection openConnectionImpl(
      String host, int port, String user, String database, Properties info, Logger logger)
      throws SQLException {
    // Extract interesting values from the info properties:
    //  - the SSL setting
    boolean requireSSL = (info.getProperty("ssl") != null);
    boolean trySSL = requireSSL; // XXX temporary until we revisit the ssl property values

    // NOTE: To simplify this code, it is assumed that if we are
    // using the V3 protocol, then the database is at least 7.4.  That
    // eliminates the need to check database versions and maintain
    // backward-compatible code here.
    //
    // Change by Chris Smith <*****@*****.**>

    if (logger.logDebug())
      logger.debug("Trying to establish a protocol version 3 connection to " + host + ":" + port);

    if (!Driver.sslEnabled()) {
      if (requireSSL)
        throw new PSQLException(
            GT.tr("The driver does not support SSL."), PSQLState.CONNECTION_FAILURE);
      trySSL = false;
    }

    //
    // Establish a connection.
    //

    PGStream newStream = null;
    try {
      newStream = new PGStream(host, port);

      // Construct and send an ssl startup packet if requested.
      if (trySSL) newStream = enableSSL(newStream, requireSSL, info, logger);

      // Construct and send a startup packet.
      String[][] params = {
        {"user", user},
        {"database", database},
        {"client_encoding", "UNICODE"},
        {"DateStyle", "ISO"},
        {"extra_float_digits", "2"}
      };

      sendStartupPacket(newStream, params, logger);

      // Do authentication (until AuthenticationOk).
      doAuthentication(newStream, user, info.getProperty("password"), logger);

      // Do final startup.
      ProtocolConnectionImpl protoConnection =
          new ProtocolConnectionImpl(newStream, user, database, info, logger);
      readStartupMessages(newStream, protoConnection, logger);

      // And we're done.
      return protoConnection;
    } catch (UnsupportedProtocolException upe) {
      // Swallow this and return null so ConnectionFactory tries the next protocol.
      if (logger.logDebug()) logger.debug("Protocol not supported, abandoning connection.");
      try {
        newStream.close();
      } catch (IOException e) {
      }
      return null;
    } catch (ConnectException cex) {
      // Added by Peter Mount <*****@*****.**>
      // ConnectException is thrown when the connection cannot be made.
      // we trap this an return a more meaningful message for the end user
      throw new PSQLException(
          GT.tr(
              "Connection refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections."),
          PSQLState.CONNECTION_REJECTED,
          cex);
    } catch (IOException ioe) {
      if (newStream != null) {
        try {
          newStream.close();
        } catch (IOException e) {
        }
      }
      throw new PSQLException(
          GT.tr("The connection attempt failed."), PSQLState.CONNECTION_UNABLE_TO_CONNECT, ioe);
    } catch (SQLException se) {
      if (newStream != null) {
        try {
          newStream.close();
        } catch (IOException e) {
        }
      }
      throw se;
    }
  }