aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Schneppe <christian@pix-art.de>2016-11-20 15:02:40 +0100
committerChristian Schneppe <christian@pix-art.de>2016-11-20 15:02:40 +0100
commitf04842b893a82583d094a9204f532841094ef525 (patch)
tree938fee79a067d7b9b5463adb003f9651f79acef3
parente9ebe0ba14ff8d3a8f5261723278f6e6e24cde15 (diff)
check if thread was interrupted before doing operations on socket
-rw-r--r--src/main/java/de/pixart/messenger/services/XmppConnectionService.java3
-rw-r--r--src/main/java/de/pixart/messenger/xmpp/XmppConnection.java165
2 files changed, 89 insertions, 79 deletions
diff --git a/src/main/java/de/pixart/messenger/services/XmppConnectionService.java b/src/main/java/de/pixart/messenger/services/XmppConnectionService.java
index d0b2718d4..cf32ad3a9 100644
--- a/src/main/java/de/pixart/messenger/services/XmppConnectionService.java
+++ b/src/main/java/de/pixart/messenger/services/XmppConnectionService.java
@@ -3046,8 +3046,6 @@ public class XmppConnectionService extends Service {
if (connection == null) {
connection = createConnection(account);
account.setXmppConnection(connection);
- } else {
- connection.interrupt();
}
if (!account.isOptionSet(Account.OPTION_DISABLED)) {
if (!force) {
@@ -3056,6 +3054,7 @@ public class XmppConnectionService extends Service {
Thread thread = new Thread(connection);
connection.setInteractive(interactive);
connection.prepareNewConnection();
+ connection.interrupt();
thread.start();
scheduleWakeUpCall(Config.CONNECT_DISCO_TIMEOUT, account.getUuid().hashCode());
} else {
diff --git a/src/main/java/de/pixart/messenger/xmpp/XmppConnection.java b/src/main/java/de/pixart/messenger/xmpp/XmppConnection.java
index dde2a639e..36fb9f078 100644
--- a/src/main/java/de/pixart/messenger/xmpp/XmppConnection.java
+++ b/src/main/java/de/pixart/messenger/xmpp/XmppConnection.java
@@ -226,7 +226,10 @@ public class XmppConnection implements Runnable {
mXmppConnectionService = service;
}
- protected void changeStatus(final Account.State nextStatus) {
+ protected synchronized void changeStatus(final Account.State nextStatus) {
+ if (Thread.currentThread().isInterrupted()) {
+ Log.d(Config.LOGTAG,account.getJid().toBareJid()+": not changing status to "+nextStatus+" because thread was interrupted");
+ }
if (account.getStatus() != nextStatus) {
if ((nextStatus == Account.State.OFFLINE)
&& (account.getStatus() != Account.State.CONNECTING)
@@ -270,6 +273,7 @@ public class XmppConnection implements Runnable {
break;
}
try {
+ Socket localSocket;
shouldAuthenticate = needsBinding = !account.isOptionSet(Account.OPTION_REGISTER);
tagReader = new XmlReader(wakeLock);
tagWriter = new TagWriter();
@@ -279,14 +283,21 @@ public class XmppConnection implements Runnable {
if (Config.XMPP_IP != null && Config.XMPP_Ports != null) {
Integer[] XMPP_Port = Config.XMPP_Ports;
Integer Port = XMPP_Port[new Random().nextInt(XMPP_Port.length)];
- socket = new Socket();
+ localSocket = new Socket();
try {
- socket.connect(new InetSocketAddress(Config.XMPP_IP, Port), Config.SOCKET_TIMEOUT * 1000);
+ Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": connect to " + Config.XMPP_IP + ":" + Port);
+ localSocket.connect(new InetSocketAddress(Config.XMPP_IP, Port), Config.SOCKET_TIMEOUT * 1000);
} catch (IOException e) {
- throw new IOException();
+ throw new UnknownHostException();
+ }
+ try {
+ startXmpp(localSocket);
+ } catch (InterruptedException e) {
+ Log.d(Config.LOGTAG,account.getJid().toBareJid()+": thread was interrupted before beginning stream");
+ return;
+ } catch (Exception e) {
+ throw new IOException(e.getMessage());
}
- Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": connect to " + Config.XMPP_IP + ":" + Port);
- startXmpp();
} else if (useTor) {
String destination;
if (account.getHostname() == null || account.getHostname().isEmpty()) {
@@ -295,8 +306,15 @@ public class XmppConnection implements Runnable {
destination = account.getHostname();
}
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": connect to " + destination + " via Tor");
- socket = SocksSocketFactory.createSocketOverTor(destination, account.getPort());
- startXmpp();
+ localSocket = SocksSocketFactory.createSocketOverTor(destination, account.getPort());
+ try {
+ startXmpp(localSocket);
+ } catch (InterruptedException e) {
+ Log.d(Config.LOGTAG,account.getJid().toBareJid()+": thread was interrupted before beginning stream");
+ return;
+ } catch (Exception e) {
+ throw new IOException(e.getMessage());
+ }
} else if (extended && account.getHostname() != null && !account.getHostname().isEmpty()) {
InetSocketAddress address = new InetSocketAddress(account.getHostname(), account.getPort());
@@ -307,33 +325,47 @@ public class XmppConnection implements Runnable {
if (features.encryptionEnabled) {
try {
final TlsFactoryVerifier tlsFactoryVerifier = getTlsFactoryVerifier();
- socket = tlsFactoryVerifier.factory.createSocket();
- socket.connect(address, Config.SOCKET_TIMEOUT * 1000);
- final SSLSession session = ((SSLSocket) socket).getSession();
+ localSocket = tlsFactoryVerifier.factory.createSocket();
+ localSocket.connect(address, Config.SOCKET_TIMEOUT * 1000);
+ final SSLSession session = ((SSLSocket) localSocket).getSession();
if (!tlsFactoryVerifier.verifier.verify(account.getServer().getDomainpart(), session)) {
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": TLS certificate verification failed");
throw new SecurityException();
}
} catch (KeyManagementException e) {
features.encryptionEnabled = false;
- socket = new Socket();
+ localSocket = new Socket();
}
} else {
- socket = new Socket();
- socket.connect(address, Config.SOCKET_TIMEOUT * 1000);
+ localSocket = new Socket();
+ localSocket.connect(address, Config.SOCKET_TIMEOUT * 1000);
}
} catch (IOException e) {
throw new UnknownHostException();
}
- startXmpp();
+ try {
+ startXmpp(localSocket);
+ } catch (InterruptedException e) {
+ Log.d(Config.LOGTAG,account.getJid().toBareJid()+": thread was interrupted before beginning stream");
+ return;
+ } catch (Exception e) {
+ throw new IOException(e.getMessage());
+ }
} else if (DNSHelper.isIp(account.getServer().toString())) {
- socket = new Socket();
+ localSocket = new Socket();
try {
- socket.connect(new InetSocketAddress(account.getServer().toString(), 5222), Config.SOCKET_TIMEOUT * 1000);
+ localSocket.connect(new InetSocketAddress(account.getServer().toString(), 5222), Config.SOCKET_TIMEOUT * 1000);
} catch (IOException e) {
throw new UnknownHostException();
}
- startXmpp();
+ try {
+ startXmpp(localSocket);
+ } catch (InterruptedException e) {
+ Log.d(Config.LOGTAG,account.getJid().toBareJid()+": thread was interrupted before beginning stream");
+ return;
+ } catch (Exception e) {
+ throw new IOException(e.getMessage());
+ }
} else {
final Bundle result = DNSHelper.getSRVRecord(account.getServer(), mXmppConnectionService);
final ArrayList<Parcelable> values = result.getParcelableArrayList("values");
@@ -369,32 +401,35 @@ public class XmppConnection implements Runnable {
}
if (!features.encryptionEnabled) {
- socket = new Socket();
- socket.connect(addr, Config.SOCKET_TIMEOUT * 1000);
+ localSocket = new Socket();
+ localSocket.connect(addr, Config.SOCKET_TIMEOUT * 1000);
} else {
final TlsFactoryVerifier tlsFactoryVerifier = getTlsFactoryVerifier();
- socket = tlsFactoryVerifier.factory.createSocket();
+ localSocket = tlsFactoryVerifier.factory.createSocket();
- if (socket == null) {
+ if (localSocket == null) {
throw new IOException("could not initialize ssl socket");
}
- SSLSocketHelper.setSecurity((SSLSocket) socket);
- SSLSocketHelper.setSNIHost(tlsFactoryVerifier.factory, (SSLSocket) socket, account.getServer().getDomainpart());
- SSLSocketHelper.setAlpnProtocol(tlsFactoryVerifier.factory, (SSLSocket) socket, "xmpp-client");
+ SSLSocketHelper.setSecurity((SSLSocket) localSocket);
+ SSLSocketHelper.setSNIHost(tlsFactoryVerifier.factory, (SSLSocket) localSocket, account.getServer().getDomainpart());
+ SSLSocketHelper.setAlpnProtocol(tlsFactoryVerifier.factory, (SSLSocket) localSocket, "xmpp-client");
- socket.connect(addr, Config.SOCKET_TIMEOUT * 1000);
+ localSocket.connect(addr, Config.SOCKET_TIMEOUT * 1000);
- if (!tlsFactoryVerifier.verifier.verify(account.getServer().getDomainpart(), ((SSLSocket) socket).getSession())) {
+ if (!tlsFactoryVerifier.verifier.verify(account.getServer().getDomainpart(), ((SSLSocket) localSocket).getSession())) {
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": TLS certificate verification failed");
throw new SecurityException();
}
}
- if (startXmpp())
+ if (startXmpp(localSocket))
break; // successfully connected to server that speaks xmpp
} catch (final SecurityException e) {
throw e;
+ } catch (InterruptedException e) {
+ Log.d(Config.LOGTAG,account.getJid().toBareJid()+": thread was interrupted before beginning stream");
+ return;
} catch (final Throwable e) {
Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": " + e.getMessage() + "(" + e.getClass().getName() + ")");
if (!iterator.hasNext()) {
@@ -406,6 +441,8 @@ public class XmppConnection implements Runnable {
processStream();
} catch (final java.lang.SecurityException e) {
this.changeStatus(Account.State.MISSING_INTERNET_PERMISSION);
+ } catch (final RegistrationNotSupportedException e) {
+ this.changeStatus(Account.State.REGISTRATION_NOT_SUPPORTED);
} catch (final IncompatibleServerException e) {
this.changeStatus(Account.State.INCOMPATIBLE_SERVER);
} catch (final SecurityException e) {
@@ -429,12 +466,17 @@ public class XmppConnection implements Runnable {
this.changeStatus(Account.State.OFFLINE);
this.attempt = Math.max(0, this.attempt - 1);
} finally {
- forceCloseSocket();
- if (wakeLock.isHeld()) {
- try {
- wakeLock.release();
- } catch (final RuntimeException ignored) {
+ if (!Thread.currentThread().isInterrupted()) {
+ forceCloseSocket();
+ if (wakeLock.isHeld()) {
+ try {
+ wakeLock.release();
+ } catch (final RuntimeException ignored) {
+ }
}
+ } else {
+ Log.d(Config.LOGTAG,account.getJid().toBareJid()+": not force closing socket and releasing wake lock because thread was interrupted");
+
}
}
}
@@ -443,27 +485,18 @@ public class XmppConnection implements Runnable {
* Starts xmpp protocol, call after connecting to socket
*
* @return true if server returns with valid xmpp, false otherwise
- * @throws IOException Unknown tag on connect
- * @throws XmlPullParserException Bad Xml
- * @throws NoSuchAlgorithmException Other error
*/
- private boolean startXmpp() throws IOException, XmlPullParserException, NoSuchAlgorithmException {
+ private boolean startXmpp(Socket socket) throws Exception {
+ if (Thread.currentThread().isInterrupted()) {
+ throw new InterruptedException();
+ }
+ this.socket = socket;
tagWriter.setOutputStream(socket.getOutputStream());
tagReader.setInputStream(socket.getInputStream());
tagWriter.beginDocument();
sendStartStream();
- Tag nextTag;
- while ((nextTag = tagReader.readTag()) != null) {
- if (nextTag.isStart("stream")) {
- return true;
- } else {
- throw new IOException("unknown tag on connect");
- }
- }
- if (socket.isConnected()) {
- socket.close();
- }
- return false;
+ final Tag tag = tagReader.readTag();
+ return tag != null && tag.isStart("stream");
}
private static class TlsFactoryVerifier {
@@ -831,10 +864,8 @@ public class XmppConnection implements Runnable {
} else {
throw new IncompatibleServerException();
}
- } else if (!this.streamFeatures.hasChild("register")
- && account.isOptionSet(Account.OPTION_REGISTER)) {
- forceCloseSocket();
- changeStatus(Account.State.REGISTRATION_NOT_SUPPORTED);
+ } else if (!this.streamFeatures.hasChild("register") && account.isOptionSet(Account.OPTION_REGISTER)) {
+ throw new RegistrationNotSupportedException();
} else if (this.streamFeatures.hasChild("mechanisms")
&& shouldAuthenticate
&& (features.encryptionEnabled || Config.ALLOW_NON_TLS_CONNECTIONS)) {
@@ -1378,30 +1409,6 @@ public class XmppConnection implements Runnable {
}
}
- public void waitForPush() {
- if (tagWriter.isActive()) {
- tagWriter.finish();
- new Thread(new Runnable() {
- @Override
- public void run() {
- try {
- while (!tagWriter.finished()) {
- Thread.sleep(10);
- }
- socket.close();
- Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": closed tcp without closing stream");
- changeStatus(Account.State.OFFLINE);
- } catch (IOException | InterruptedException e) {
- Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": error while closing socket for waitForPush()");
- }
- }
- }).start();
- } else {
- forceCloseSocket();
- Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": closed tcp without closing stream (no waiting)");
- }
- }
-
private void forceCloseSocket() {
if (socket != null) {
try {
@@ -1589,6 +1596,10 @@ public class XmppConnection implements Runnable {
}
+ private class RegistrationNotSupportedException extends IOException {
+
+ }
+
public enum Identity {
FACEBOOK,
SLACK,