private void onSecurityPreambleError(Channel ch, Set<String> serverPrincipals,
    IOException error) {
    assert eventLoop.inEventLoop();
    LOG.debug("Error when trying to do a security preamble call to {}", remoteId.address, error);
    if (ConnectionUtils.isUnexpectedPreambleHeaderException(error)) {
      // this means we are connecting to an old server which does not support the security
      // preamble call, so we should fallback to randomly select a principal to use
      // TODO: find a way to reconnect without failing all the pending calls, for now, when we
      // reach here, shutdown should have already been scheduled
      return;
    }
    if (IPCUtil.isSecurityNotEnabledException(error)) {
      // server tells us security is not enabled, then we should check whether fallback to
      // simple is allowed, if so we just go without security, otherwise we should fail the
      // negotiation immediately
      if (rpcClient.fallbackAllowed) {
        // TODO: just change the preamble and skip the fallback to simple logic, for now, just
        // select the first principal can finish the connection setup, but waste one client
        // message
        saslNegotiate(ch, serverPrincipals.iterator().next());
      } else {
        failInit(ch, new FallbackDisallowedException());
      }
      return;
    }
    // usually we should not reach here, but for robust, just randomly select a principal to
    // connect
    saslNegotiate(ch, randomSelect(serverPrincipals));
  }
RPC connection implementation based on netty.
<p/>
Most operations are executed in handlers. Netty handler is always executed in the same
thread(EventLoop) so no lock is needed.
<p/>
<strong>Implementation assumptions:</strong> All the private methods should be called in the
{@link #eventLoop} thread, otherwise there will be races.
@since 2.0.0
hbase-client/src/main/java/org/apache/hadoop/hbase/ipc/NettyRpcConnection.java