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.");
}
}
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();
}
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);
}
}
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);
}
}
}
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;
}
Aggregations