private void saslNegotiate(Channel ch) throws IOException {
    assert eventLoop.inEventLoop();
    Set<String> serverPrincipals = getServerPrincipals();
    if (serverPrincipals.size() == 1) {
      saslNegotiate(ch, serverPrincipals.iterator().next());
      return;
    }
    // this means we use kerberos authentication and there are multiple server principal candidates,
    // in this way we need to send a special preamble header to get server principal from server
    Call securityPreambleCall = createSecurityPreambleCall(call -> {
      assert eventLoop.inEventLoop();
      if (call.error != null) {
        onSecurityPreambleError(ch, serverPrincipals, call.error);
      } else {
        onSecurityPreambleFinish(ch, serverPrincipals, call);
      }
    });
    PreambleCallHandler.setup(ch.pipeline(), rpcClient.readTO, this,
      RpcClient.SECURITY_PREAMBLE_HEADER, securityPreambleCall);
  }
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