2003-01-13 17:58:47 +01:00
|
|
|
/**
|
|
|
|
*
|
2007-02-12 01:59:05 +01:00
|
|
|
* Copyright 2003-2007 Jive Software.
|
2003-01-13 17:58:47 +01:00
|
|
|
*
|
2014-02-17 18:57:38 +01:00
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
2004-11-03 00:53:30 +01:00
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
2003-01-13 17:58:47 +01:00
|
|
|
*
|
2004-11-03 00:53:30 +01:00
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
2003-01-13 17:58:47 +01:00
|
|
|
*
|
2004-11-03 00:53:30 +01:00
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
2003-01-13 17:58:47 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
package org.jivesoftware.smack;
|
|
|
|
|
2014-03-14 00:25:22 +01:00
|
|
|
import org.jivesoftware.smack.packet.IQ;
|
|
|
|
import org.jivesoftware.smack.packet.Packet;
|
|
|
|
import org.jivesoftware.smack.packet.Presence;
|
2013-06-22 19:01:40 +02:00
|
|
|
import org.jivesoftware.smack.parsing.ParsingExceptionCallback;
|
2013-10-06 01:14:24 +02:00
|
|
|
import org.jivesoftware.smack.parsing.UnparsablePacket;
|
2010-02-09 13:24:24 +01:00
|
|
|
import org.jivesoftware.smack.sasl.SASLMechanism.Challenge;
|
2014-03-12 11:50:05 +01:00
|
|
|
import org.jivesoftware.smack.sasl.SASLMechanism.SASLFailure;
|
2010-02-09 13:24:24 +01:00
|
|
|
import org.jivesoftware.smack.sasl.SASLMechanism.Success;
|
2005-08-27 04:29:04 +02:00
|
|
|
import org.jivesoftware.smack.util.PacketParserUtils;
|
2014-03-12 11:50:05 +01:00
|
|
|
|
|
|
|
import org.jivesoftware.smack.SmackException.NoResponseException;
|
|
|
|
import org.jivesoftware.smack.SmackException.SecurityRequiredException;
|
|
|
|
import org.jivesoftware.smack.XMPPException.StreamErrorException;
|
2014-02-20 13:38:12 +01:00
|
|
|
import org.xmlpull.v1.XmlPullParserFactory;
|
2005-08-27 04:29:04 +02:00
|
|
|
import org.xmlpull.v1.XmlPullParser;
|
|
|
|
import org.xmlpull.v1.XmlPullParserException;
|
2003-04-08 17:32:26 +02:00
|
|
|
|
2003-01-13 17:58:47 +01:00
|
|
|
/**
|
2003-05-01 04:06:21 +02:00
|
|
|
* Listens for XML traffic from the XMPP server and parses it into packet objects.
|
2010-02-09 12:55:56 +01:00
|
|
|
* The packet reader also invokes all packet listeners and collectors.<p>
|
2003-05-01 04:06:21 +02:00
|
|
|
*
|
2014-03-10 09:45:50 +01:00
|
|
|
* @see XMPPConnection#createPacketCollector
|
|
|
|
* @see XMPPConnection#addPacketListener
|
2003-01-13 17:58:47 +01:00
|
|
|
* @author Matt Tucker
|
|
|
|
*/
|
2003-01-17 08:11:33 +01:00
|
|
|
class PacketReader {
|
2003-01-13 17:58:47 +01:00
|
|
|
|
2006-09-14 21:16:40 +02:00
|
|
|
private Thread readerThread;
|
2003-01-13 17:58:47 +01:00
|
|
|
|
2014-04-09 12:16:44 +02:00
|
|
|
private XMPPTCPConnection connection;
|
2003-01-13 17:58:47 +01:00
|
|
|
private XmlPullParser parser;
|
|
|
|
|
2014-04-26 19:00:58 +02:00
|
|
|
/**
|
|
|
|
* Set to true if the last features stanza from the server has been parsed. A XMPP connection
|
|
|
|
* handshake can invoke multiple features stanzas, e.g. when TLS is activated a second feature
|
|
|
|
* stanza is send by the server. This is set to true once the last feature stanza has been
|
|
|
|
* parsed.
|
|
|
|
*/
|
|
|
|
private volatile boolean lastFeaturesParsed;
|
|
|
|
|
|
|
|
volatile boolean done;
|
2003-01-13 17:58:47 +01:00
|
|
|
|
2014-04-26 19:08:50 +02:00
|
|
|
protected PacketReader(final XMPPTCPConnection connection) throws XmlPullParserException {
|
2003-01-13 17:58:47 +01:00
|
|
|
this.connection = connection;
|
2006-09-14 21:16:40 +02:00
|
|
|
this.init();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initializes the reader in order to be used. The reader is initialized during the
|
|
|
|
* first connection and when reconnecting due to an abruptly disconnection.
|
2014-04-26 19:08:50 +02:00
|
|
|
*
|
|
|
|
* @throws XmlPullParserException if the parser could not be reset.
|
2006-09-14 21:16:40 +02:00
|
|
|
*/
|
2014-04-26 19:08:50 +02:00
|
|
|
protected void init() throws XmlPullParserException {
|
2006-09-14 21:16:40 +02:00
|
|
|
done = false;
|
2014-04-26 19:00:58 +02:00
|
|
|
lastFeaturesParsed = false;
|
2003-01-13 17:58:47 +01:00
|
|
|
|
|
|
|
readerThread = new Thread() {
|
|
|
|
public void run() {
|
2006-09-14 21:16:40 +02:00
|
|
|
parsePackets(this);
|
2003-01-13 17:58:47 +01:00
|
|
|
}
|
|
|
|
};
|
2007-02-04 21:52:45 +01:00
|
|
|
readerThread.setName("Smack Packet Reader (" + connection.connectionCounterValue + ")");
|
2003-01-13 17:58:47 +01:00
|
|
|
readerThread.setDaemon(true);
|
|
|
|
|
2005-12-08 22:10:41 +01:00
|
|
|
resetParser();
|
2003-01-13 17:58:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Starts the packet reader thread and returns once a connection to the server
|
2014-04-26 19:00:58 +02:00
|
|
|
* has been established or if the server's features could not be parsed within
|
|
|
|
* the connection's PacketReplyTimeout.
|
|
|
|
*
|
2014-03-12 11:50:05 +01:00
|
|
|
* @throws NoResponseException if the server fails to send an opening stream back
|
2014-04-26 19:00:58 +02:00
|
|
|
* within packetReplyTimeout.
|
2003-01-13 17:58:47 +01:00
|
|
|
*/
|
2014-03-12 11:50:05 +01:00
|
|
|
synchronized public void startup() throws NoResponseException {
|
2003-01-13 17:58:47 +01:00
|
|
|
readerThread.start();
|
2013-03-22 19:14:08 +01:00
|
|
|
// Wait for stream tag before returning. We'll wait a couple of seconds before
|
2003-01-13 17:58:47 +01:00
|
|
|
// giving up and throwing an error.
|
|
|
|
try {
|
2006-09-13 19:58:28 +02:00
|
|
|
// A waiting thread may be woken up before the wait time or a notify
|
|
|
|
// (although this is a rare thing). Therefore, we continue waiting
|
2014-04-26 19:00:58 +02:00
|
|
|
// until either the server's features have been parsed (and hence a notify was
|
2006-09-13 19:58:28 +02:00
|
|
|
// made) or the total wait time has elapsed.
|
2014-04-26 19:00:58 +02:00
|
|
|
wait(connection.getPacketReplyTimeout());
|
2003-01-13 17:58:47 +01:00
|
|
|
}
|
2005-09-05 22:00:45 +02:00
|
|
|
catch (InterruptedException ie) {
|
|
|
|
// Ignore.
|
|
|
|
}
|
2014-04-26 19:00:58 +02:00
|
|
|
if (!lastFeaturesParsed) {
|
2014-03-12 11:50:05 +01:00
|
|
|
throw new NoResponseException();
|
2003-01-13 17:58:47 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Shuts the packet reader down.
|
|
|
|
*/
|
|
|
|
public void shutdown() {
|
2003-08-20 18:29:46 +02:00
|
|
|
// Notify connection listeners of the connection closing if done hasn't already been set.
|
|
|
|
if (!done) {
|
2014-03-14 01:48:33 +01:00
|
|
|
connection.callConnectionClosedListener();
|
2003-07-16 04:49:43 +02:00
|
|
|
}
|
2003-08-20 18:29:46 +02:00
|
|
|
done = true;
|
2003-01-13 17:58:47 +01:00
|
|
|
}
|
|
|
|
|
2005-08-27 04:29:04 +02:00
|
|
|
/**
|
|
|
|
* Resets the parser using the latest connection's reader. Reseting the parser is necessary
|
|
|
|
* when the plain connection has been secured or when a new opening stream element is going
|
|
|
|
* to be sent by the server.
|
2014-04-26 19:08:50 +02:00
|
|
|
*
|
|
|
|
* @throws XmlPullParserException XmlPullParserException if the parser could not be reset.
|
2005-08-27 04:29:04 +02:00
|
|
|
*/
|
2014-04-26 19:08:50 +02:00
|
|
|
private void resetParser() throws XmlPullParserException {
|
|
|
|
parser = XmlPullParserFactory.newInstance().newPullParser();
|
|
|
|
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
|
|
|
|
parser.setInput(connection.reader);
|
2005-08-27 04:29:04 +02:00
|
|
|
}
|
|
|
|
|
2003-01-13 17:58:47 +01:00
|
|
|
/**
|
|
|
|
* Parse top-level packets in order to process them further.
|
2006-09-14 21:16:40 +02:00
|
|
|
*
|
|
|
|
* @param thread the thread that is being used by the reader to parse incoming packets.
|
2003-01-13 17:58:47 +01:00
|
|
|
*/
|
2006-09-14 21:16:40 +02:00
|
|
|
private void parsePackets(Thread thread) {
|
2003-01-13 17:58:47 +01:00
|
|
|
try {
|
|
|
|
int eventType = parser.getEventType();
|
|
|
|
do {
|
2003-04-08 17:32:26 +02:00
|
|
|
if (eventType == XmlPullParser.START_TAG) {
|
2013-06-22 19:01:40 +02:00
|
|
|
int parserDepth = parser.getDepth();
|
|
|
|
ParsingExceptionCallback callback = connection.getParsingExceptionCallback();
|
2003-01-13 17:58:47 +01:00
|
|
|
if (parser.getName().equals("message")) {
|
2013-06-22 19:01:40 +02:00
|
|
|
Packet packet;
|
|
|
|
try {
|
|
|
|
packet = PacketParserUtils.parseMessage(parser);
|
|
|
|
} catch (Exception e) {
|
|
|
|
String content = PacketParserUtils.parseContentDepth(parser, parserDepth);
|
2013-10-06 01:14:24 +02:00
|
|
|
UnparsablePacket message = new UnparsablePacket(content, e);
|
2013-06-22 19:01:40 +02:00
|
|
|
if (callback != null) {
|
2013-10-06 01:14:24 +02:00
|
|
|
callback.handleUnparsablePacket(message);
|
2013-06-22 19:01:40 +02:00
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
2014-03-14 00:25:22 +01:00
|
|
|
connection.processPacket(packet);
|
2003-01-13 17:58:47 +01:00
|
|
|
}
|
|
|
|
else if (parser.getName().equals("iq")) {
|
2013-06-22 19:01:40 +02:00
|
|
|
IQ iq;
|
|
|
|
try {
|
|
|
|
iq = PacketParserUtils.parseIQ(parser, connection);
|
|
|
|
} catch (Exception e) {
|
|
|
|
String content = PacketParserUtils.parseContentDepth(parser, parserDepth);
|
2013-10-06 01:14:24 +02:00
|
|
|
UnparsablePacket message = new UnparsablePacket(content, e);
|
2013-06-22 19:01:40 +02:00
|
|
|
if (callback != null) {
|
2013-10-06 01:14:24 +02:00
|
|
|
callback.handleUnparsablePacket(message);
|
2013-06-22 19:01:40 +02:00
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
2014-03-14 00:25:22 +01:00
|
|
|
connection.processPacket(iq);
|
2003-01-13 17:58:47 +01:00
|
|
|
}
|
|
|
|
else if (parser.getName().equals("presence")) {
|
2013-06-22 19:01:40 +02:00
|
|
|
Presence presence;
|
|
|
|
try {
|
|
|
|
presence = PacketParserUtils.parsePresence(parser);
|
|
|
|
} catch (Exception e) {
|
|
|
|
String content = PacketParserUtils.parseContentDepth(parser, parserDepth);
|
2013-10-06 01:14:24 +02:00
|
|
|
UnparsablePacket message = new UnparsablePacket(content, e);
|
2013-06-22 19:01:40 +02:00
|
|
|
if (callback != null) {
|
2013-10-06 01:14:24 +02:00
|
|
|
callback.handleUnparsablePacket(message);
|
2013-06-22 19:01:40 +02:00
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
2014-03-14 00:25:22 +01:00
|
|
|
connection.processPacket(presence);
|
2003-01-13 17:58:47 +01:00
|
|
|
}
|
|
|
|
// We found an opening stream. Record information about it, then notify
|
|
|
|
// the connectionID lock so that the packet reader startup can finish.
|
|
|
|
else if (parser.getName().equals("stream")) {
|
|
|
|
// Ensure the correct jabber:client namespace is being used.
|
|
|
|
if ("jabber:client".equals(parser.getNamespace(null))) {
|
|
|
|
// Get the connection id.
|
|
|
|
for (int i=0; i<parser.getAttributeCount(); i++) {
|
|
|
|
if (parser.getAttributeName(i).equals("id")) {
|
2005-09-06 00:03:47 +02:00
|
|
|
// Save the connectionID
|
2014-04-26 19:00:58 +02:00
|
|
|
connection.connectionID = parser.getAttributeValue(i);
|
2003-01-13 17:58:47 +01:00
|
|
|
}
|
2003-10-03 02:47:45 +02:00
|
|
|
else if (parser.getAttributeName(i).equals("from")) {
|
|
|
|
// Use the server name that the server says that it is.
|
2010-02-09 12:55:56 +01:00
|
|
|
connection.config.setServiceName(parser.getAttributeValue(i));
|
2003-10-03 02:47:45 +02:00
|
|
|
}
|
2003-01-13 17:58:47 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2005-11-08 21:10:33 +01:00
|
|
|
else if (parser.getName().equals("error")) {
|
2014-03-12 11:50:05 +01:00
|
|
|
throw new StreamErrorException(PacketParserUtils.parseStreamError(parser));
|
2005-11-08 21:10:33 +01:00
|
|
|
}
|
2005-08-27 04:29:04 +02:00
|
|
|
else if (parser.getName().equals("features")) {
|
2006-09-13 19:58:28 +02:00
|
|
|
parseFeatures(parser);
|
2005-08-27 04:29:04 +02:00
|
|
|
}
|
|
|
|
else if (parser.getName().equals("proceed")) {
|
|
|
|
// Secure the connection by negotiating TLS
|
|
|
|
connection.proceedTLSReceived();
|
|
|
|
// Reset the state of the parser since a new stream element is going
|
|
|
|
// to be sent by the server
|
|
|
|
resetParser();
|
|
|
|
}
|
|
|
|
else if (parser.getName().equals("failure")) {
|
2006-01-16 18:34:56 +01:00
|
|
|
String namespace = parser.getNamespace(null);
|
|
|
|
if ("urn:ietf:params:xml:ns:xmpp-tls".equals(namespace)) {
|
2005-09-13 22:05:29 +02:00
|
|
|
// TLS negotiation has failed. The server will close the connection
|
|
|
|
throw new Exception("TLS negotiation has failed");
|
|
|
|
}
|
2006-01-16 18:34:56 +01:00
|
|
|
else if ("http://jabber.org/protocol/compress".equals(namespace)) {
|
|
|
|
// Stream compression has been denied. This is a recoverable
|
|
|
|
// situation. It is still possible to authenticate and
|
|
|
|
// use the connection but using an uncompressed connection
|
|
|
|
connection.streamCompressionDenied();
|
|
|
|
}
|
2005-09-13 22:05:29 +02:00
|
|
|
else {
|
|
|
|
// SASL authentication has failed. The server may close the connection
|
|
|
|
// depending on the number of retries
|
2014-03-12 11:50:05 +01:00
|
|
|
final SASLFailure failure = PacketParserUtils.parseSASLFailure(parser);
|
2014-03-14 00:25:22 +01:00
|
|
|
connection.processPacket(failure);
|
2014-03-12 11:50:05 +01:00
|
|
|
connection.getSASLAuthentication().authenticationFailed(failure);
|
2005-09-13 22:05:29 +02:00
|
|
|
}
|
2005-08-27 04:29:04 +02:00
|
|
|
}
|
|
|
|
else if (parser.getName().equals("challenge")) {
|
|
|
|
// The server is challenging the SASL authentication made by the client
|
2010-02-09 13:24:24 +01:00
|
|
|
String challengeData = parser.nextText();
|
2014-03-14 00:25:22 +01:00
|
|
|
connection.processPacket(new Challenge(challengeData));
|
2010-02-09 13:24:24 +01:00
|
|
|
connection.getSASLAuthentication().challengeReceived(challengeData);
|
2005-08-27 04:29:04 +02:00
|
|
|
}
|
|
|
|
else if (parser.getName().equals("success")) {
|
2014-03-14 00:25:22 +01:00
|
|
|
connection.processPacket(new Success(parser.nextText()));
|
2010-02-09 13:24:24 +01:00
|
|
|
// We now need to bind a resource for the connection
|
|
|
|
// Open a new stream and wait for the response
|
|
|
|
connection.packetWriter.openStream();
|
|
|
|
// Reset the state of the parser since a new stream element is going
|
|
|
|
// to be sent by the server
|
|
|
|
resetParser();
|
|
|
|
// The SASL authentication with the server was successful. The next step
|
|
|
|
// will be to bind the resource
|
|
|
|
connection.getSASLAuthentication().authenticated();
|
2005-08-27 04:29:04 +02:00
|
|
|
}
|
2006-01-16 18:34:56 +01:00
|
|
|
else if (parser.getName().equals("compressed")) {
|
|
|
|
// Server confirmed that it's possible to use stream compression. Start
|
|
|
|
// stream compression
|
|
|
|
connection.startStreamCompression();
|
|
|
|
// Reset the state of the parser since a new stream element is going
|
|
|
|
// to be sent by the server
|
|
|
|
resetParser();
|
|
|
|
}
|
2003-01-13 17:58:47 +01:00
|
|
|
}
|
2003-04-08 17:32:26 +02:00
|
|
|
else if (eventType == XmlPullParser.END_TAG) {
|
2003-01-13 17:58:47 +01:00
|
|
|
if (parser.getName().equals("stream")) {
|
2006-09-14 21:16:40 +02:00
|
|
|
// Disconnect the connection
|
|
|
|
connection.disconnect();
|
2003-01-13 17:58:47 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
eventType = parser.next();
|
2006-09-14 21:16:40 +02:00
|
|
|
} while (!done && eventType != XmlPullParser.END_DOCUMENT && thread == readerThread);
|
2003-01-13 17:58:47 +01:00
|
|
|
}
|
|
|
|
catch (Exception e) {
|
2013-01-06 15:02:44 +01:00
|
|
|
// The exception can be ignored if the the connection is 'done'
|
|
|
|
// or if the it was caused because the socket got closed
|
|
|
|
if (!(done || connection.isSocketClosed())) {
|
2003-09-19 00:35:42 +02:00
|
|
|
// Close the connection and notify connection listeners of the
|
|
|
|
// error.
|
2013-03-18 20:58:48 +01:00
|
|
|
connection.notifyConnectionError(e);
|
2003-01-13 17:58:47 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-08-27 04:29:04 +02:00
|
|
|
private void parseFeatures(XmlPullParser parser) throws Exception {
|
2005-09-06 00:03:47 +02:00
|
|
|
boolean startTLSReceived = false;
|
2007-01-11 20:01:24 +01:00
|
|
|
boolean startTLSRequired = false;
|
2005-09-06 00:03:47 +02:00
|
|
|
boolean done = false;
|
2005-08-27 04:29:04 +02:00
|
|
|
while (!done) {
|
|
|
|
int eventType = parser.next();
|
|
|
|
|
|
|
|
if (eventType == XmlPullParser.START_TAG) {
|
|
|
|
if (parser.getName().equals("starttls")) {
|
2005-09-06 00:03:47 +02:00
|
|
|
startTLSReceived = true;
|
2005-08-27 04:29:04 +02:00
|
|
|
}
|
2005-09-06 00:03:47 +02:00
|
|
|
else if (parser.getName().equals("mechanisms")) {
|
|
|
|
// The server is reporting available SASL mechanisms. Store this information
|
2005-08-27 04:29:04 +02:00
|
|
|
// which will be used later while logging (i.e. authenticating) into
|
|
|
|
// the server
|
|
|
|
connection.getSASLAuthentication()
|
2010-02-09 13:11:39 +01:00
|
|
|
.setAvailableSASLMethods(PacketParserUtils.parseMechanisms(parser));
|
2005-08-27 04:29:04 +02:00
|
|
|
}
|
|
|
|
else if (parser.getName().equals("bind")) {
|
|
|
|
// The server requires the client to bind a resource to the stream
|
|
|
|
connection.getSASLAuthentication().bindingRequired();
|
|
|
|
}
|
2013-03-18 09:50:48 +01:00
|
|
|
// Set the entity caps node for the server if one is send
|
|
|
|
// See http://xmpp.org/extensions/xep-0115.html#stream
|
|
|
|
else if (parser.getName().equals("c")) {
|
|
|
|
String node = parser.getAttributeValue(null, "node");
|
|
|
|
String ver = parser.getAttributeValue(null, "ver");
|
|
|
|
if (ver != null && node != null) {
|
|
|
|
String capsNode = node + "#" + ver;
|
|
|
|
// In order to avoid a dependency from smack to smackx
|
|
|
|
// we have to set the services caps node in the connection
|
|
|
|
// and not directly in the EntityCapsManager
|
|
|
|
connection.setServiceCapsNode(capsNode);
|
|
|
|
}
|
|
|
|
}
|
2005-08-27 04:29:04 +02:00
|
|
|
else if (parser.getName().equals("session")) {
|
|
|
|
// The server supports sessions
|
|
|
|
connection.getSASLAuthentication().sessionsSupported();
|
|
|
|
}
|
2013-11-10 15:02:57 +01:00
|
|
|
else if (parser.getName().equals("ver")) {
|
|
|
|
if (parser.getNamespace().equals("urn:xmpp:features:rosterver")) {
|
|
|
|
connection.setRosterVersioningSupported();
|
|
|
|
}
|
|
|
|
}
|
2006-01-16 18:34:56 +01:00
|
|
|
else if (parser.getName().equals("compression")) {
|
|
|
|
// The server supports stream compression
|
2010-02-09 13:11:39 +01:00
|
|
|
connection.setAvailableCompressionMethods(PacketParserUtils.parseCompressionMethods(parser));
|
2006-01-16 18:34:56 +01:00
|
|
|
}
|
2006-08-03 19:04:01 +02:00
|
|
|
else if (parser.getName().equals("register")) {
|
2014-03-17 20:46:08 +01:00
|
|
|
AccountManager.getInstance(connection).setSupportsAccountCreation(true);
|
2006-08-03 19:04:01 +02:00
|
|
|
}
|
2005-08-27 04:29:04 +02:00
|
|
|
}
|
|
|
|
else if (eventType == XmlPullParser.END_TAG) {
|
2007-01-11 20:01:24 +01:00
|
|
|
if (parser.getName().equals("starttls")) {
|
|
|
|
// Confirm the server that we want to use TLS
|
|
|
|
connection.startTLSReceived(startTLSRequired);
|
|
|
|
}
|
|
|
|
else if (parser.getName().equals("required") && startTLSReceived) {
|
|
|
|
startTLSRequired = true;
|
|
|
|
}
|
|
|
|
else if (parser.getName().equals("features")) {
|
2005-08-27 04:29:04 +02:00
|
|
|
done = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-01-11 20:01:24 +01:00
|
|
|
|
|
|
|
// If TLS is required but the server doesn't offer it, disconnect
|
|
|
|
// from the server and throw an error. First check if we've already negotiated TLS
|
|
|
|
// and are secure, however (features get parsed a second time after TLS is established).
|
|
|
|
if (!connection.isSecureConnection()) {
|
|
|
|
if (!startTLSReceived && connection.getConfiguration().getSecurityMode() ==
|
|
|
|
ConnectionConfiguration.SecurityMode.required)
|
|
|
|
{
|
2014-03-12 11:50:05 +01:00
|
|
|
throw new SecurityRequiredException();
|
2007-01-11 20:01:24 +01:00
|
|
|
}
|
|
|
|
}
|
2014-03-14 00:25:22 +01:00
|
|
|
|
2014-04-26 18:47:47 +02:00
|
|
|
// Release the lock after TLS has been negotiated or we are not interested in TLS. If the
|
|
|
|
// server announced TLS and we choose to use it, by sending 'starttls', which the server
|
|
|
|
// replied with 'proceed', the server is required to send a new stream features element that
|
|
|
|
// "MUST NOT include the STARTTLS feature" (RFC6120 5.4.3.3. 5.). We are therefore save to
|
|
|
|
// release the connection lock once either TLS is disabled or we received a features stanza
|
|
|
|
// without starttls.
|
2007-01-11 20:01:24 +01:00
|
|
|
if (!startTLSReceived || connection.getConfiguration().getSecurityMode() ==
|
|
|
|
ConnectionConfiguration.SecurityMode.disabled)
|
|
|
|
{
|
2014-04-26 19:00:58 +02:00
|
|
|
lastFeaturesParsed = true;
|
2014-04-26 18:47:47 +02:00
|
|
|
// This synchronized block prevents this thread from calling notify() before the other
|
|
|
|
// thread had called wait() (it would cause an Exception if wait() hadn't been called)
|
|
|
|
synchronized (this) {
|
|
|
|
notify();
|
|
|
|
}
|
2005-09-06 00:03:47 +02:00
|
|
|
}
|
2005-08-27 04:29:04 +02:00
|
|
|
}
|
2013-01-06 15:02:44 +01:00
|
|
|
}
|