/**
   * Creates a new outgoing connection to the specified hostname if no one exists. The port of the
   * remote server could be configured by setting the <b>xmpp.server.socket.remotePort</b> property
   * or otherwise the standard port 5269 will be used. Either a new connection was created or
   * already existed the specified hostname will be authenticated with the remote server. Once
   * authenticated the remote server will start accepting packets from the specified domain.
   *
   * <p>The Server Dialback method is currently the only implemented method for server-to-server
   * authentication. This implies that the remote server will ask the Authoritative Server to verify
   * the domain to authenticate. Most probably this (local) server will act as the Authoritative
   * Server. See {@link IncomingServerSession} for more information.
   *
   * @param domain the local domain to authenticate with the remote server.
   * @param hostname the hostname of the remote server.
   * @return True if the domain was authenticated by the remote server.
   */
  public static OutgoingServerSession authenticateDomain(String domain, String hostname) {
    if (hostname == null || hostname.length() == 0 || hostname.trim().indexOf(' ') > -1) {
      // Do nothing if the target hostname is empty, null or contains whitespaces
      return null;
    }
    try {
      // Check if the remote hostname is in the blacklist
      if (!RemoteServerManager.canAccess(hostname)) {
        return null;
      }

      OutgoingServerSession session;
      // Check if a session, that is using server dialback, already exists to the desired
      // hostname (i.e. remote server). If no one exists then create a new session. The same
      // session will be used for the same hostname for all the domains to authenticate
      SessionManager sessionManager = SessionManager.getInstance();
      if (sessionManager == null) {
        // Server is shutting down while we are trying to create a new s2s connection
        return null;
      }
      session = sessionManager.getOutgoingServerSession(hostname);
      if (session == null) {
        // Try locating if the remote server has previously authenticated with this server
        for (IncomingServerSession incomingSession :
            sessionManager.getIncomingServerSessions(hostname)) {
          for (String otherHostname : incomingSession.getValidatedDomains()) {
            session = sessionManager.getOutgoingServerSession(otherHostname);
            if (session != null) {
              if (session.isUsingServerDialback()) {
                // A session to the same remote server but with different hostname
                // was found. Use this session.
                break;
              } else {
                session = null;
              }
            }
          }
        }
      }
      if (session == null) {
        int port = RemoteServerManager.getPortForServer(hostname);
        session = createOutgoingSession(domain, hostname, port);
        if (session != null) {
          // Add the validated domain as an authenticated domain
          session.addAuthenticatedDomain(domain);
          // Add the new hostname to the list of names that the server may have
          session.addHostname(hostname);
          // Notify the SessionManager that a new session has been created
          sessionManager.outgoingServerSessionCreated((LocalOutgoingServerSession) session);
          return session;
        } else {
          Log.warn("Fail to connect to {} for {}", hostname, domain);
          return null;
        }
      }
      // A session already exists. The session was established using server dialback so
      // it is possible to do piggybacking to authenticate more domains
      if (session.getAuthenticatedDomains().contains(domain)
          && session.getHostnames().contains(hostname)) {
        // Do nothing since the domain has already been authenticated
        return session;
      }
      // A session already exists so authenticate the domain using that session
      if (session.authenticateSubdomain(domain, hostname)) return session;
    } catch (Exception e) {
      Log.error("Error authenticating domain with remote server: " + hostname, e);
    }
    return null;
  }