Search in sources :

Example 1 with XmppTransportException

use of com.googlecode.asmack.connection.XmppTransportException in project AsmackService by rtreffer.

the class FeatureNegotiationEngine method open.

/*
     * From RFC 3920-bis-13#page-26
     * 4.2.7. Flow Chart
     * 
     *                         +------------+
     *                         |  open TCP  |
     *                         | connection |
     *                         +------------+
     *                               |
     *                               | <------------ open() starts here
     *                               |
     *                               v
     *                        +---------------+
     *                        | send initial  |<-------------------------+
     *                        | stream header |                          ^
     *                        +---------------+                          |
     *                               |                                   |
     *                               v                                   |
     *                       +------------------+                        |
     *                       | receive response |                        |
     *                       | stream header    |                        |
     *                       +------------------+                        |
     *                               |                                   |
     *                               v                                   |
     *                        +----------------+                         |
     *                        | receive stream |                         |
     *    +------------------>| features       |                         |
     *    ^                   +----------------+                         |
     *    |                          |                                   |
     *    |                          v                                   |
     *    |       +<-----------------+                                   |
     *    |       |                                                      |
     *    |    {empty?} ----> {all voluntary?} ----> {some mandatory?}   |
     *    |       |      no          |          no         |             |
     *    |       | yes              | yes                 | yes         |
     *    |       |                  v                     v             |
     *    |       |           +---------------+    +----------------+    |
     *    |       |           | MAY negotiate |    | MUST negotiate |    |
     *    |       |           | any or none   |    | one feature    |    |
     *    |       |           +---------------+    +----------------+    |
     *    |       |                  |                     |             |
     *    |       v                  v                     |             |
     *    |   +----------+      +-----------+              |             |
     *    |   | process  |<-----| negotiate |              |             |
     *    |   | complete |  no  | a feature |              |             |
     *    |   +----------+      +-----------+              |             |
     *    |                          |                     |             |
     *    |                     yes  |                     |             |
     *    |                          v                     v             |
     *    |                          +--------->+<---------+             |
     *    |                                     |                        |
     *    |                                     v                        |
     *    +<-------------------------- {restart mandatory?} ------------>+
     *                   no                                     yes
     * 
     * The "open" method starts directly after opening the TCP streams,
     * negotiates the connection and returns true if the xmpp stream is ready
     * for a bind.
     * 
     * The usual way to bind is
     * if (streamEngine.open(account)) {
     *     String resource = streamEngine.bind(account.getResource);
     * }
     * 
     * Interresting and available features that require restarts:
     * - SASL
     * - TLS
     * - Compression
     */
/**
     * <p>Open a connection for a given account. This will run the full
     * negotiation with the following precedence:
     * <ol>
     *     <li>TLS (if available)</li>
     *     <li>Compression (if available)</li>
     *     <li>SASL</li>
     * <ol></p>
     *
     * <p><b>Note:</b> Servers should not offer compression befor SASL is
     * completed. This is not violated by the rule, mobile devices love xml
     * compression, thus a higher preference. Everything will work as expected
     * when compression is offered after SASL.</p>
     *
     * <p>This method requires a call to bind (if you wish to bind) afterwards.
     * </p>
     * 
     * @param account XmppAccount The account used for negotiation.
     * @throws XmppException In case of an error.
     */
public void open(XmppAccount account) throws XmppException {
    boolean rerun = true;
    boolean canBind = false;
    while (rerun) {
        try {
            rerun = false;
            xmppOutput.open(XMPPUtils.getDomain(account.getJid()), null);
            xmppInput.readOpening();
            Node features = null;
            do {
                Node stanza = xmppInput.nextStanza().getDocumentNode();
                if (XMLUtils.isInstance(stanza, "http://etherx.jabber.org/streams", "features")) {
                    features = stanza;
                }
            } while (features == null);
            // check basic stream features
            rosterVersioningSupported |= XMLUtils.hasChild(features, "urn:xmpp:features:rosterver", "ver");
            sessionsSupported |= XMLUtils.hasChild(features, "urn:ietf:params:xml:ns:xmpp-session", "session");
            canBind |= XMLUtils.hasChild(features, "urn:ietf:params:xml:ns:xmpp-bind", "bind");
            hasTLS = XMLUtils.hasChild(features, "urn:ietf:params:xml:ns:xmpp-tls", "starttls");
            Node compression = XMLUtils.getFirstChild(features, "http://jabber.org/features/compress", "compression");
            if (compression != null) {
                NodeList methods = compression.getChildNodes();
                for (int i = 0, l = methods.getLength(); i < l; i++) {
                    Node method = methods.item(i);
                    if (method.getNodeType() != Node.ELEMENT_NODE) {
                        continue;
                    }
                    if (!"method".equals(method.getNodeName())) {
                        continue;
                    }
                    String methodName = method.getFirstChild().getNodeValue();
                    methodName = methodName.trim();
                    compressionSupported |= "zlib".equals(methodName);
                }
            }
            Node saslMechanisms = XMLUtils.getFirstChild(features, "urn:ietf:params:xml:ns:xmpp-sasl", "mechanisms");
            SASLSupported |= saslMechanisms != null;
            if (hasTLS && !secure) {
                // enable tls
                xmppOutput.sendUnchecked("<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>");
                boolean startTLS = XMLUtils.isInstance(xmppInput.nextStanza().getDocumentNode(), "urn:ietf:params:xml:ns:xmpp-tls", "proceed");
                if (startTLS) {
                    startTLS();
                    secure = true;
                    rerun = true;
                    continue;
                }
            }
            if (compressionSupported && !compressed && ZLibOutputStream.SUPPORTED) {
                startCompress();
                rerun = true;
                continue;
            }
            if (SASLSupported && !authenticated) {
                if (saslLogin(saslMechanisms, account)) {
                    authenticated = true;
                    rerun = true;
                    continue;
                }
            }
        } catch (IllegalArgumentException e) {
            throw new XmppMalformedException("Can't negotiate features", e);
        } catch (IllegalStateException e) {
            throw new XmppMalformedException("Can't negotiate features", e);
        } catch (IOException e) {
            throw new XmppTransportException("Can't negotiate features", e);
        } catch (XmlPullParserException e) {
            throw new XmppMalformedException("Can't negotiate features", e);
        } catch (NoSuchAlgorithmException e) {
            // Should never happen - TLS not available?
            throw new XmppTransportException("Can't enable tls", e);
        } catch (KeyManagementException e) {
            throw new XmppTransportException("Can't trust server", e);
        }
    }
    if (!canBind) {
        throw new XmppTransportException("Couldn't reach bind state.");
    }
}
Also used : Node(org.w3c.dom.Node) NodeList(org.w3c.dom.NodeList) XmppTransportException(com.googlecode.asmack.connection.XmppTransportException) IOException(java.io.IOException) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) KeyManagementException(java.security.KeyManagementException) XmppMalformedException(com.googlecode.asmack.XmppMalformedException) XmlPullParserException(org.xmlpull.v1.XmlPullParserException)

Example 2 with XmppTransportException

use of com.googlecode.asmack.connection.XmppTransportException in project AsmackService by rtreffer.

the class TcpConnection method connect.

/**
     * Method connect.
     * @param sink StanzaSink
     * @throws XmppException
     * @see com.googlecode.asmack.connection.Connection#connect(StanzaSink)
     */
public void connect(StanzaSink sink) throws XmppException {
    String connection = account.getConnection();
    // cut "tcp:"
    connection = connection.substring(4).trim();
    // Target
    int port = 5222;
    InetAddress addresse;
    // Get Port
    int split = connection.lastIndexOf(':');
    if (split != -1) {
        String portNumber = connection.substring(split + 1);
        port = Integer.parseInt(portNumber);
        connection = connection.substring(0, split);
    }
    // Get Host IPs
    InetAddress[] inetAddresses;
    if (connection.charAt(0) == '[' && connection.charAt(connection.length()) == ']') {
        // IPv6
        if (split == -1) {
            throw new IllegalStateException("Not a valid tcp uri (" + account.getConnection() + ")");
        }
        String ipv6 = connection.substring(1, connection.length() - 1);
        try {
            inetAddresses = InetAddress.getAllByName(ipv6);
        } catch (UnknownHostException e) {
            throw new XmppTransportException("can't resolve host", e);
        }
    } else {
        // prefer IPv4, IPv6 if no IPv4 record found
        try {
            inetAddresses = Inet4Address.getAllByName(connection);
            if (inetAddresses.length == 0) {
                inetAddresses = Inet6Address.getAllByName(connection);
            }
        } catch (UnknownHostException uhe) {
            try {
                inetAddresses = Inet6Address.getAllByName(connection);
            } catch (UnknownHostException e) {
                throw new XmppTransportException("can't resolve host", e);
            }
        }
    }
    if (inetAddresses == null || inetAddresses.length == 0) {
        throw new XmppTransportException("Couldn't resolve " + connection);
    }
    if (inetAddresses.length == 1) {
        addresse = inetAddresses[0];
    } else {
        int index = (int) (Math.random() * Integer.MAX_VALUE);
        index %= inetAddresses.length;
        addresse = inetAddresses[index];
    }
    connect(addresse, port);
    new ConncetionPullToSinkPushThread(this, xmppInput, sink).start();
}
Also used : UnknownHostException(java.net.UnknownHostException) XmppTransportException(com.googlecode.asmack.connection.XmppTransportException) InetAddress(java.net.InetAddress)

Example 3 with XmppTransportException

use of com.googlecode.asmack.connection.XmppTransportException in project AsmackService by rtreffer.

the class XmppInputStream method attach.

/**
     * Attach to an underlying input stream, usually done during feature
     * negotiation as some features require stream resets.
     * @param in InputStream The new underlying input stream.
     * @throws XmppTransportException In case of a transport error.
     */
public void attach(InputStream in) throws XmppTransportException {
    this.inputStream = in;
    try {
        parser = XMLUtils.getXMLPullParser();
        parser.setInput(in, "UTF-8");
    } catch (XmlPullParserException e) {
        throw new XmppTransportException("Can't initialize pull parser", e);
    }
}
Also used : XmppTransportException(com.googlecode.asmack.connection.XmppTransportException) XmlPullParserException(org.xmlpull.v1.XmlPullParserException)

Example 4 with XmppTransportException

use of com.googlecode.asmack.connection.XmppTransportException in project AsmackService by rtreffer.

the class XmppOutputStream method sendUnchecked.

/**
     * Send a string fragment to the server, flushing the stream afterwards.
     * @param stanza String The stanza string.
     * @throws XmppTransportException In case of a transport exception.
     */
public void sendUnchecked(String stanza) throws XmppTransportException {
    Log.d(TAG, stanza);
    synchronized (outputStream) {
        try {
            outputStream.write(stanza.getBytes());
            outputStream.flush();
        } catch (IOException e) {
            throw new XmppTransportException("Stanza sending failed", e);
        }
    }
}
Also used : XmppTransportException(com.googlecode.asmack.connection.XmppTransportException) IOException(java.io.IOException)

Example 5 with XmppTransportException

use of com.googlecode.asmack.connection.XmppTransportException in project AsmackService by rtreffer.

the class FeatureNegotiationEngine method saslLogin.

/**
     * Run a sasl based login. Most sals parts are handled by
     * {@link SASLEngine#login(XmppInputStream, XmppOutputStream, java.util.Set, XmppAccount)}.
     * @param saslMechanisms Node The DOM node of the sasl mechanisms.
     * @param account XmppAccount The xmpp account to use.
     * @return boolean True on success. False on failore.
     * @throws XmppException On critical connection errors-
     */
protected boolean saslLogin(Node saslMechanisms, XmppAccount account) throws XmppException {
    NodeList nodes = saslMechanisms.getChildNodes();
    HashSet<String> methods = new HashSet<String>(13);
    for (int i = 0, l = nodes.getLength(); i < l; i++) {
        Node node = nodes.item(i);
        if (!XMLUtils.isInstance(node, null, "mechanism")) {
            continue;
        }
        methods.add(node.getFirstChild().getNodeValue().toUpperCase().trim());
    }
    if (SASLEngine.login(xmppInput, xmppOutput, methods, account)) {
        xmppInput.detach();
        try {
            xmppOutput.detach();
            xmppInput.attach(inputStream);
            xmppOutput.attach(outputStream, true, false);
        } catch (IllegalArgumentException e) {
            throw new XmppMalformedException("Please report", e);
        } catch (IllegalStateException e) {
            throw new XmppMalformedException("Please report", e);
        } catch (IOException e) {
            throw new XmppTransportException("Couldn't restart connection", e);
        }
        return true;
    }
    return false;
}
Also used : XmppMalformedException(com.googlecode.asmack.XmppMalformedException) NodeList(org.w3c.dom.NodeList) Node(org.w3c.dom.Node) XmppTransportException(com.googlecode.asmack.connection.XmppTransportException) IOException(java.io.IOException) HashSet(java.util.HashSet)

Aggregations

XmppTransportException (com.googlecode.asmack.connection.XmppTransportException)9 IOException (java.io.IOException)5 XmlPullParserException (org.xmlpull.v1.XmlPullParserException)5 XmppMalformedException (com.googlecode.asmack.XmppMalformedException)4 NoSuchAlgorithmException (java.security.NoSuchAlgorithmException)2 Node (org.w3c.dom.Node)2 NodeList (org.w3c.dom.NodeList)2 Stanza (com.googlecode.asmack.Stanza)1 InetAddress (java.net.InetAddress)1 UnknownHostException (java.net.UnknownHostException)1 KeyManagementException (java.security.KeyManagementException)1 HashSet (java.util.HashSet)1 SocketFactory (javax.net.SocketFactory)1