3

I intend to use Smack to send messages through Firebase CCS. I modified a simple CCS client for my Web App but when I try to make connection, it results in exception. I am using Smack 4.2.0

Here is the process of connection.

1) The connection method which is in my client:

public void connect() throws XMPPException{
        try{
            config = XMPPTCPConnectionConfiguration.builder()
                    .setPort(Config.FCM_PORT)
                    .setHost("fcm-xmpp.googleapis.com")
                    .setXmppDomain("googleapis.com")
                    .setSecurityMode(/*Default; Explicit setting for emphasis*/SecurityMode.ifpossible)
                    .setSendPresence(true)
                    .setUsernameAndPassword(fcmServerUsername, mApiKey)
                    .setSocketFactory(SSLSocketFactory.getDefault())
                    .setDebuggerEnabled(mDebuggable)/* Launch a window with info about packets sent and received */
                    .build();
        }
        catch(XmppStringprepException e){
            e.printStackTrace();
        }

        connection = new XMPPTCPConnection(config);


        // Configuring Automatic reconnection
        ReconnectionManager manager = ReconnectionManager.getInstanceFor(connection);
        manager.setReconnectionPolicy(ReconnectionManager.ReconnectionPolicy.RANDOM_INCREASING_DELAY);
        manager.enableAutomaticReconnection();

        // Connect now then login
        try{
            connection.connect();
            connection.login();
        }
        // TODO: Handle the exceptions if possible appropriately
        catch(SmackException sme){
            logger.severe(sme.getMessage());
            sme.printStackTrace();
        }
        catch(IOException ioe){
            logger.severe(ioe.getMessage());
            ioe.printStackTrace();
        }
        catch(InterruptedException ie){
            logger.severe("Connection got interrupted!!");
            ie.printStackTrace();
        }
    }

2) I traced the exception and I got it here: (Smack's source)

At the line - HostAddress hostAddress = DNSUtil.getDNSResolver().lookupHostAddress(config.host, config.port, failedAddresses, config.getDnssecMode());

// AbstractXMPPConnection.java
protected List<HostAddress> populateHostAddresses() {
        List<HostAddress> failedAddresses = new LinkedList<>();
        if (config.hostAddress != null) {
            hostAddresses = new ArrayList<>(1);
            HostAddress hostAddress = new HostAddress(config.port, config.hostAddress);
            hostAddresses.add(hostAddress);
        }
        else if (config.host != null) {
            hostAddresses = new ArrayList<HostAddress>(1);
            HostAddress hostAddress = DNSUtil.getDNSResolver().lookupHostAddress(config.host, config.port, failedAddresses, config.getDnssecMode());
            if (hostAddress != null) {
                hostAddresses.add(hostAddress);
            }
        } else {
            // N.B.: Important to use config.serviceName and not AbstractXMPPConnection.serviceName
            hostAddresses = DNSUtil.resolveXMPPServiceDomain(config.getXMPPServiceDomain().toString(), failedAddresses, config.getDnssecMode());
        }
        // Either the populated host addresses are not empty *or* there must be at least one failed address.
        assert(!hostAddresses.isEmpty() || !failedAddresses.isEmpty());
        return failedAddresses;
    }

The exception is NullPointerException and I found that getDNSResolver() returns null. Of all the sources I have referenced, there wasn't anything related to DNS resolver as it is supposed to be internally handled by Smack. So my question is, have I missed out some crucial configuration or step in making the connection?

EDIT: I asked here because Smack is vast lib and there might some config someone knows that I might have missed. I am unable to set DNSResolver directly

Manish Kumar Sharma
  • 12,982
  • 9
  • 58
  • 105
  • @MartinW : I asked here because Smack is vast lib and there might some config someone knows that I might have missed. I am unable to set DNSResolver directly. – Manish Kumar Sharma Apr 23 '17 at 12:26
  • 1
    So the actually problem isn't the NPE, it's is that you need help configuring a library properly. Try asking about that. – The Head Rush Apr 23 '17 at 12:32

2 Answers2

4

EDIT : ANSWER UPDATE

This is NOT a bug in Smack's source as their Upgrade Guide for 4.2.0 explicitly mentions:

**

API Changes

**

Warning: This list may not be complete

Introduced ConnectionConfiguration.setHostAddress(InetAddress)

In previous versions of Smack, ConnectionConfiguration.setHost(String) could be used to set the XMPP service's host IP address. This is no longer possible due to the added DNSSEC support. You have to use the new connection configuration ConnectionConfiguration.setHostAddress(InetAddress) instead.


This seems to be a bug because I solved it by providing the Host Address (which was supposed to be inferred from {Host, Domain}). So, how did I know to provide the host address?

The trick lies here: (Smack' source)

// AbstractXMPPConnection.java

if (config.hostAddress != null) {
            hostAddresses = new ArrayList<>(1);
            HostAddress hostAddress = new HostAddress(config.port, config.hostAddress);
            hostAddresses.add(hostAddress);
        }
        else if (config.host != null) {
            hostAddresses = new ArrayList<HostAddress>(1);
            HostAddress hostAddress = DNSUtil.getDNSResolver().lookupHostAddress(config.host, config.port, failedAddresses, config.getDnssecMode());
            if (hostAddress != null) {
                hostAddresses.add(hostAddress);
            }
        } else {
            // N.B.: Important to use config.serviceName and not AbstractXMPPConnection.serviceName
            hostAddresses = DNSUtil.resolveXMPPServiceDomain(config.getXMPPServiceDomain().toString(), failedAddresses, config.getDnssecMode());
        }

You can see the if, else-if blocks here and since the exception arises in the else if (config.host != null) block, I provided hostAddress so that it never enters that block and it worked.

I know this is sort of a hack around the actual problem but this seems to be a bug in Smack 4.2.0 unless someone disproves me otherwise.

Bonus info: If after rectifying this problem, you get another exception in Base 64 encoding during login, refer to this - XMPP client using Smack 4.1 giving NullPointerException during login

Community
  • 1
  • 1
Manish Kumar Sharma
  • 12,982
  • 9
  • 58
  • 105
4

Not sure in 4.2.0 but in 4.2.2 (and newer), you will need smack-resolver-dnsjava-4.2.2.jar to be in your classpath, smack calls DNSUtil which is included in the package, if the class doesn't exist it returns NullPointerException.

Hope this help! David

Feng David
  • 119
  • 3
  • for a long time I iwas expecting to find this error. thanks implementation 'org.igniterealtime.smack:smack-resolver-dnsjava:4.2.3' – Alp Altunel Oct 10 '19 at 08:51