private void setupIOstreams(Call connectionRegistryCall) throws IOException {
    if (socket != null) {
      // The connection is already available. Perfect.
      return;
    }

    if (this.rpcClient.failedServers.isFailedServer(remoteId.getAddress())) {
      if (LOG.isDebugEnabled()) {
        LOG.debug("Not trying to connect to " + remoteId.getAddress()
          + " this server is in the failed servers list");
      }
      throw new FailedServerException(
        "This server is in the failed servers list: " + remoteId.getAddress());
    }

    try {
      if (LOG.isDebugEnabled()) {
        LOG.debug("Connecting to " + remoteId.getAddress());
      }

      short numRetries = 0;
      int reloginMaxRetries = this.rpcClient.conf.getInt("hbase.security.relogin.maxretries", 5);
      while (true) {
        setupConnection();
        InputStream inStream = NetUtils.getInputStream(socket);
        // This creates a socket with a write timeout. This timeout cannot be changed.
        OutputStream outStream = NetUtils.getOutputStream(socket, this.rpcClient.writeTO);
        if (connectionRegistryCall != null) {
          getConnectionRegistry(inStream, outStream, connectionRegistryCall);
          closeSocket();
          return;
        }

        if (useSasl) {
          UserGroupInformation ticket = provider.getRealUser(remoteId.ticket);
          boolean continueSasl;
          if (ticket == null) {
            throw new FatalConnectionException("ticket/user is null");
          }
          String serverPrincipal = chooseServerPrincipal(inStream, outStream);
          // Write out the preamble -- MAGIC, version, and auth to use.
          writeConnectionHeaderPreamble(outStream);
          try {
            final InputStream in2 = inStream;
            final OutputStream out2 = outStream;
            continueSasl = ticket.doAs(new PrivilegedExceptionAction<Boolean>() {
              @Override
              public Boolean run() throws IOException {
                return setupSaslConnection(in2, out2, serverPrincipal);
              }
            });
          } catch (Exception ex) {
            ExceptionUtil.rethrowIfInterrupt(ex);
            saslNegotiationDone(serverPrincipal, false);
            handleSaslConnectionFailure(numRetries++, reloginMaxRetries, ex, ticket,
              serverPrincipal);
            continue;
          }
          saslNegotiationDone(serverPrincipal, true);
          if (continueSasl) {
            // Sasl connect is successful. Let's set up Sasl i/o streams.
            inStream = saslRpcClient.getInputStream();
            outStream = saslRpcClient.getOutputStream();
          } else {
            // fall back to simple auth because server told us so.
            // do not change authMethod and useSasl here, we should start from secure when
            // reconnecting because regionserver may change its sasl config after restart.
            saslRpcClient = null;
          }
        } else {
          // Write out the preamble -- MAGIC, version, and auth to use.
          writeConnectionHeaderPreamble(outStream);
        }
        createStreams(inStream, outStream);
        // Now write out the connection header
        writeConnectionHeader();
        // process the response from server for connection header if necessary
        processResponseForConnectionHeader();
        break;
      }
    } catch (Throwable t) {
      closeSocket();
      IOException e = ExceptionUtil.asInterrupt(t);
      if (e == null) {
        this.rpcClient.failedServers.addToFailedServers(remoteId.getAddress(), t);
        if (t instanceof LinkageError) {
          // probably the hbase hadoop version does not match the running hadoop version
          e = new DoNotRetryIOException(t);
        } else if (t instanceof IOException) {
          e = (IOException) t;
        } else {
          e = new IOException("Could not set up IO Streams to " + remoteId.getAddress(), t);
        }
      }
      throw e;
    }

    // start the receiver thread after the socket connection has been set up
    thread = new Thread(this, threadName);
    thread.setDaemon(true);
    thread.start();
  }
If multiple clients with the same principal try to connect to the same server at the same time,
the server assumes a replay attack is in progress. This is a feature of kerberos. In order to
work around this, what is done is that the client backs off randomly and tries to initiate the
connection again. The other problem is to do with ticket expiry. To handle that, a relogin is
attempted.
<p>
The retry logic is governed by the {@link SaslClientAuthenticationProvider#canRetry()} method.
Some providers have the ability to obtain new credentials and then re-attempt to authenticate
with HBase services. Other providers will continue to fail if they failed the first time -- for
those, we want to fail-fast.
</p>
hbase-client/src/main/java/org/apache/hadoop/hbase/ipc/BlockingRpcConnection.java