wait up to 2s to let server close socket before force closing
This commit is contained in:
parent
94e0c6b38c
commit
d348780dfc
|
@ -63,6 +63,7 @@ import eu.siacs.conversations.entities.Account;
|
||||||
import eu.siacs.conversations.entities.Message;
|
import eu.siacs.conversations.entities.Message;
|
||||||
import eu.siacs.conversations.entities.ServiceDiscoveryResult;
|
import eu.siacs.conversations.entities.ServiceDiscoveryResult;
|
||||||
import eu.siacs.conversations.generator.IqGenerator;
|
import eu.siacs.conversations.generator.IqGenerator;
|
||||||
|
import eu.siacs.conversations.persistance.FileBackend;
|
||||||
import eu.siacs.conversations.services.NotificationService;
|
import eu.siacs.conversations.services.NotificationService;
|
||||||
import eu.siacs.conversations.services.XmppConnectionService;
|
import eu.siacs.conversations.services.XmppConnectionService;
|
||||||
import eu.siacs.conversations.utils.CryptoHelper;
|
import eu.siacs.conversations.utils.CryptoHelper;
|
||||||
|
@ -155,11 +156,11 @@ public class XmppConnection implements Runnable {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public X509Certificate[] getCertificateChain(String alias) {
|
public X509Certificate[] getCertificateChain(String alias) {
|
||||||
Log.d(Config.LOGTAG,"getting certificate chain");
|
Log.d(Config.LOGTAG, "getting certificate chain");
|
||||||
try {
|
try {
|
||||||
return KeyChain.getCertificateChain(mXmppConnectionService, alias);
|
return KeyChain.getCertificateChain(mXmppConnectionService, alias);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.d(Config.LOGTAG,e.getMessage());
|
Log.d(Config.LOGTAG, e.getMessage());
|
||||||
return new X509Certificate[0];
|
return new X509Certificate[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -185,7 +186,7 @@ public class XmppConnection implements Runnable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public final OnIqPacketReceived registrationResponseListener = new OnIqPacketReceived() {
|
public final OnIqPacketReceived registrationResponseListener = new OnIqPacketReceived() {
|
||||||
@Override
|
@Override
|
||||||
public void onIqPacketReceived(Account account, IqPacket packet) {
|
public void onIqPacketReceived(Account account, IqPacket packet) {
|
||||||
if (packet.getType() == IqPacket.TYPE.RESULT) {
|
if (packet.getType() == IqPacket.TYPE.RESULT) {
|
||||||
|
@ -291,7 +292,7 @@ public class XmppConnection implements Runnable {
|
||||||
try {
|
try {
|
||||||
startXmpp(localSocket);
|
startXmpp(localSocket);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": thread was interrupted before beginning stream");
|
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": thread was interrupted before beginning stream");
|
||||||
return;
|
return;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new IOException(e.getMessage());
|
throw new IOException(e.getMessage());
|
||||||
|
@ -327,7 +328,7 @@ public class XmppConnection implements Runnable {
|
||||||
try {
|
try {
|
||||||
startXmpp(localSocket);
|
startXmpp(localSocket);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": thread was interrupted before beginning stream");
|
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": thread was interrupted before beginning stream");
|
||||||
return;
|
return;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new IOException(e.getMessage());
|
throw new IOException(e.getMessage());
|
||||||
|
@ -342,7 +343,7 @@ public class XmppConnection implements Runnable {
|
||||||
try {
|
try {
|
||||||
startXmpp(localSocket);
|
startXmpp(localSocket);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": thread was interrupted before beginning stream");
|
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": thread was interrupted before beginning stream");
|
||||||
return;
|
return;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new IOException(e.getMessage());
|
throw new IOException(e.getMessage());
|
||||||
|
@ -404,7 +405,7 @@ public class XmppConnection implements Runnable {
|
||||||
} catch (final StateChangingException e) {
|
} catch (final StateChangingException e) {
|
||||||
throw e;
|
throw e;
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": thread was interrupted before beginning stream");
|
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": thread was interrupted before beginning stream");
|
||||||
return;
|
return;
|
||||||
} catch (final Throwable e) {
|
} catch (final Throwable e) {
|
||||||
Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": " + e.getMessage() + "(" + e.getClass().getName() + ")");
|
Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": " + e.getMessage() + "(" + e.getClass().getName() + ")");
|
||||||
|
@ -415,9 +416,9 @@ public class XmppConnection implements Runnable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
processStream();
|
processStream();
|
||||||
} catch (final SecurityException e) {
|
} catch (final SecurityException e) {
|
||||||
this.changeStatus(Account.State.MISSING_INTERNET_PERMISSION);
|
this.changeStatus(Account.State.MISSING_INTERNET_PERMISSION);
|
||||||
} catch(final StateChangingException e) {
|
} catch (final StateChangingException e) {
|
||||||
this.changeStatus(e.state);
|
this.changeStatus(e.state);
|
||||||
} catch (final Resolver.NetworkIsUnreachableException e) {
|
} catch (final Resolver.NetworkIsUnreachableException e) {
|
||||||
this.changeStatus(Account.State.NETWORK_IS_UNREACHABLE);
|
this.changeStatus(Account.State.NETWORK_IS_UNREACHABLE);
|
||||||
|
@ -439,15 +440,16 @@ public class XmppConnection implements Runnable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": not force closing socket and releasing wake lock (is held="+wakeLock.isHeld()+") because thread was interrupted");
|
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": not force closing socket and releasing wake lock (is held=" + wakeLock.isHeld() + ") because thread was interrupted");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts xmpp protocol, call after connecting to socket
|
* Starts xmpp protocol, call after connecting to socket
|
||||||
|
*
|
||||||
* @return true if server returns with valid xmpp, false otherwise
|
* @return true if server returns with valid xmpp, false otherwise
|
||||||
*/
|
*/
|
||||||
private boolean startXmpp(Socket socket) throws Exception {
|
private boolean startXmpp(Socket socket) throws Exception {
|
||||||
if (Thread.currentThread().isInterrupted()) {
|
if (Thread.currentThread().isInterrupted()) {
|
||||||
throw new InterruptedException();
|
throw new InterruptedException();
|
||||||
|
@ -499,7 +501,7 @@ public class XmppConnection implements Runnable {
|
||||||
public void run() {
|
public void run() {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
if (Thread.currentThread().isInterrupted()) {
|
if (Thread.currentThread().isInterrupted()) {
|
||||||
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": aborting connect because thread was interrupted");
|
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": aborting connect because thread was interrupted");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
forceCloseSocket();
|
forceCloseSocket();
|
||||||
|
@ -556,7 +558,7 @@ public class XmppConnection implements Runnable {
|
||||||
}
|
}
|
||||||
} else if (nextTag.isStart("challenge")) {
|
} else if (nextTag.isStart("challenge")) {
|
||||||
final String challenge = tagReader.readElement(nextTag).getContent();
|
final String challenge = tagReader.readElement(nextTag).getContent();
|
||||||
final Element response = new Element("response",Namespace.SASL);
|
final Element response = new Element("response", Namespace.SASL);
|
||||||
try {
|
try {
|
||||||
response.setContent(saslMechanism.getResponse(challenge));
|
response.setContent(saslMechanism.getResponse(challenge));
|
||||||
} catch (final SaslMechanism.AuthenticationException e) {
|
} catch (final SaslMechanism.AuthenticationException e) {
|
||||||
|
@ -613,7 +615,7 @@ public class XmppConnection implements Runnable {
|
||||||
}
|
}
|
||||||
} catch (final NumberFormatException ignored) {
|
} catch (final NumberFormatException ignored) {
|
||||||
}
|
}
|
||||||
Log.d(Config.LOGTAG, account.getJid().toBareJid()+ ": online with resource " + account.getResource());
|
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": online with resource " + account.getResource());
|
||||||
changeStatus(Account.State.ONLINE);
|
changeStatus(Account.State.ONLINE);
|
||||||
} else if (nextTag.isStart("r")) {
|
} else if (nextTag.isStart("r")) {
|
||||||
tagReader.readElement(nextTag);
|
tagReader.readElement(nextTag);
|
||||||
|
@ -645,13 +647,13 @@ public class XmppConnection implements Runnable {
|
||||||
acknowledgeStanzaUpTo(serverSequence);
|
acknowledgeStanzaUpTo(serverSequence);
|
||||||
}
|
}
|
||||||
} catch (NumberFormatException | NullPointerException e) {
|
} catch (NumberFormatException | NullPointerException e) {
|
||||||
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": server send ack without sequence number");
|
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": server send ack without sequence number");
|
||||||
}
|
}
|
||||||
} else if (nextTag.isStart("failed")) {
|
} else if (nextTag.isStart("failed")) {
|
||||||
Element failed = tagReader.readElement(nextTag);
|
Element failed = tagReader.readElement(nextTag);
|
||||||
try {
|
try {
|
||||||
final int serverCount = Integer.parseInt(failed.getAttribute("h"));
|
final int serverCount = Integer.parseInt(failed.getAttribute("h"));
|
||||||
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": resumption failed but server acknowledged stanza #"+serverCount);
|
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": resumption failed but server acknowledged stanza #" + serverCount);
|
||||||
synchronized (this.mStanzaQueue) {
|
synchronized (this.mStanzaQueue) {
|
||||||
acknowledgeStanzaUpTo(serverCount);
|
acknowledgeStanzaUpTo(serverCount);
|
||||||
}
|
}
|
||||||
|
@ -689,7 +691,7 @@ public class XmppConnection implements Runnable {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Element processPacket(final Tag currentTag, final int packetType)
|
private Element processPacket(final Tag currentTag, final int packetType)
|
||||||
throws XmlPullParserException, IOException {
|
throws XmlPullParserException, IOException {
|
||||||
Element element;
|
Element element;
|
||||||
switch (packetType) {
|
switch (packetType) {
|
||||||
case PACKET_IQ:
|
case PACKET_IQ:
|
||||||
|
@ -716,10 +718,10 @@ public class XmppConnection implements Runnable {
|
||||||
if (packetType == PACKET_IQ
|
if (packetType == PACKET_IQ
|
||||||
&& "jingle".equals(child.getName())
|
&& "jingle".equals(child.getName())
|
||||||
&& ("set".equalsIgnoreCase(type) || "get"
|
&& ("set".equalsIgnoreCase(type) || "get"
|
||||||
.equalsIgnoreCase(type))) {
|
.equalsIgnoreCase(type))) {
|
||||||
element = new JinglePacket();
|
element = new JinglePacket();
|
||||||
element.setAttributes(currentTag.getAttributes());
|
element.setAttributes(currentTag.getAttributes());
|
||||||
}
|
}
|
||||||
element.addChild(child);
|
element.addChild(child);
|
||||||
}
|
}
|
||||||
nextTag = tagReader.readTag();
|
nextTag = tagReader.readTag();
|
||||||
|
@ -734,7 +736,7 @@ public class XmppConnection implements Runnable {
|
||||||
++stanzasReceived;
|
++stanzasReceived;
|
||||||
lastPacketReceived = SystemClock.elapsedRealtime();
|
lastPacketReceived = SystemClock.elapsedRealtime();
|
||||||
if (Config.BACKGROUND_STANZA_LOGGING && mXmppConnectionService.checkListeners()) {
|
if (Config.BACKGROUND_STANZA_LOGGING && mXmppConnectionService.checkListeners()) {
|
||||||
Log.d(Config.LOGTAG,"[background stanza] "+element);
|
Log.d(Config.LOGTAG, "[background stanza] " + element);
|
||||||
}
|
}
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
@ -748,7 +750,7 @@ public class XmppConnection implements Runnable {
|
||||||
|
|
||||||
if (packet instanceof JinglePacket) {
|
if (packet instanceof JinglePacket) {
|
||||||
if (this.jingleListener != null) {
|
if (this.jingleListener != null) {
|
||||||
this.jingleListener.onJinglePacketReceived(account,(JinglePacket) packet);
|
this.jingleListener.onJinglePacketReceived(account, (JinglePacket) packet);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
OnIqPacketReceived callback = null;
|
OnIqPacketReceived callback = null;
|
||||||
|
@ -786,7 +788,7 @@ public class XmppConnection implements Runnable {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processMessage(final Tag currentTag) throws XmlPullParserException, IOException {
|
private void processMessage(final Tag currentTag) throws XmlPullParserException, IOException {
|
||||||
final MessagePacket packet = (MessagePacket) processPacket(currentTag,PACKET_MESSAGE);
|
final MessagePacket packet = (MessagePacket) processPacket(currentTag, PACKET_MESSAGE);
|
||||||
this.messageListener.onMessagePacketReceived(account, packet);
|
this.messageListener.onMessagePacketReceived(account, packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -802,7 +804,6 @@ public class XmppConnection implements Runnable {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void switchOverToTls(final Tag currentTag) throws XmlPullParserException, IOException {
|
private void switchOverToTls(final Tag currentTag) throws XmlPullParserException, IOException {
|
||||||
tagReader.readTag();
|
tagReader.readTag();
|
||||||
try {
|
try {
|
||||||
|
@ -822,13 +823,13 @@ public class XmppConnection implements Runnable {
|
||||||
SSLSocketHelper.setSecurity(sslSocket);
|
SSLSocketHelper.setSecurity(sslSocket);
|
||||||
|
|
||||||
if (!tlsFactoryVerifier.verifier.verify(account.getServer().getDomainpart(), this.verifiedHostname, sslSocket.getSession())) {
|
if (!tlsFactoryVerifier.verifier.verify(account.getServer().getDomainpart(), this.verifiedHostname, sslSocket.getSession())) {
|
||||||
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": TLS certificate verification failed");
|
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": TLS certificate verification failed");
|
||||||
throw new StateChangingException(Account.State.TLS_ERROR);
|
throw new StateChangingException(Account.State.TLS_ERROR);
|
||||||
}
|
}
|
||||||
tagReader.setInputStream(sslSocket.getInputStream());
|
tagReader.setInputStream(sslSocket.getInputStream());
|
||||||
tagWriter.setOutputStream(sslSocket.getOutputStream());
|
tagWriter.setOutputStream(sslSocket.getOutputStream());
|
||||||
sendStartStream();
|
sendStartStream();
|
||||||
Log.d(Config.LOGTAG, account.getJid().toBareJid()+ ": TLS connection established");
|
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": TLS connection established");
|
||||||
features.encryptionEnabled = true;
|
features.encryptionEnabled = true;
|
||||||
final Tag tag = tagReader.readTag();
|
final Tag tag = tagReader.readTag();
|
||||||
if (tag != null && tag.isStart("stream")) {
|
if (tag != null && tag.isStart("stream")) {
|
||||||
|
@ -844,7 +845,7 @@ public class XmppConnection implements Runnable {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processStreamFeatures(final Tag currentTag)
|
private void processStreamFeatures(final Tag currentTag)
|
||||||
throws XmlPullParserException, IOException {
|
throws XmlPullParserException, IOException {
|
||||||
this.streamFeatures = tagReader.readElement(currentTag);
|
this.streamFeatures = tagReader.readElement(currentTag);
|
||||||
if (this.streamFeatures.hasChild("starttls") && !features.encryptionEnabled) {
|
if (this.streamFeatures.hasChild("starttls") && !features.encryptionEnabled) {
|
||||||
sendStartTLS();
|
sendStartTLS();
|
||||||
|
@ -862,7 +863,7 @@ public class XmppConnection implements Runnable {
|
||||||
authenticate();
|
authenticate();
|
||||||
} else if (this.streamFeatures.hasChild("sm", "urn:xmpp:sm:" + smVersion) && streamId != null) {
|
} else if (this.streamFeatures.hasChild("sm", "urn:xmpp:sm:" + smVersion) && streamId != null) {
|
||||||
if (Config.EXTENDED_SM_LOGGING) {
|
if (Config.EXTENDED_SM_LOGGING) {
|
||||||
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": resuming after stanza #"+stanzasReceived);
|
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": resuming after stanza #" + stanzasReceived);
|
||||||
}
|
}
|
||||||
final ResumePacket resume = new ResumePacket(this.streamId, stanzasReceived, smVersion);
|
final ResumePacket resume = new ResumePacket(this.streamId, stanzasReceived, smVersion);
|
||||||
this.mSmCatchupMessageCounter.set(0);
|
this.mSmCatchupMessageCounter.set(0);
|
||||||
|
@ -880,7 +881,7 @@ public class XmppConnection implements Runnable {
|
||||||
private void authenticate() throws IOException {
|
private void authenticate() throws IOException {
|
||||||
final List<String> mechanisms = extractMechanisms(streamFeatures
|
final List<String> mechanisms = extractMechanisms(streamFeatures
|
||||||
.findChild("mechanisms"));
|
.findChild("mechanisms"));
|
||||||
final Element auth = new Element("auth",Namespace.SASL);
|
final Element auth = new Element("auth", Namespace.SASL);
|
||||||
if (mechanisms.contains("EXTERNAL") && account.getPrivateKeyAlias() != null) {
|
if (mechanisms.contains("EXTERNAL") && account.getPrivateKeyAlias() != null) {
|
||||||
saslMechanism = new External(tagWriter, account, mXmppConnectionService.getRNG());
|
saslMechanism = new External(tagWriter, account, mXmppConnectionService.getRNG());
|
||||||
} else if (mechanisms.contains("SCRAM-SHA-256")) {
|
} else if (mechanisms.contains("SCRAM-SHA-256")) {
|
||||||
|
@ -979,12 +980,12 @@ public class XmppConnection implements Runnable {
|
||||||
if (failed) {
|
if (failed) {
|
||||||
final Element query = packet.query();
|
final Element query = packet.query();
|
||||||
final String instructions = query.findChildContent("instructions");
|
final String instructions = query.findChildContent("instructions");
|
||||||
final Element oob = query.findChild("x",Namespace.OOB);
|
final Element oob = query.findChild("x", Namespace.OOB);
|
||||||
final String url = oob == null ? null : oob.findChildContent("url");
|
final String url = oob == null ? null : oob.findChildContent("url");
|
||||||
if (url == null && instructions != null) {
|
if (url == null && instructions != null) {
|
||||||
Matcher matcher = Patterns.AUTOLINK_WEB_URL.matcher(instructions);
|
Matcher matcher = Patterns.AUTOLINK_WEB_URL.matcher(instructions);
|
||||||
if (matcher.find()) {
|
if (matcher.find()) {
|
||||||
setAccountCreationFailed(instructions.substring(matcher.start(),matcher.end()));
|
setAccountCreationFailed(instructions.substring(matcher.start(), matcher.end()));
|
||||||
} else {
|
} else {
|
||||||
setAccountCreationFailed(null);
|
setAccountCreationFailed(null);
|
||||||
}
|
}
|
||||||
|
@ -1004,7 +1005,7 @@ public class XmppConnection implements Runnable {
|
||||||
changeStatus(Account.State.REGISTRATION_FAILED);
|
changeStatus(Account.State.REGISTRATION_FAILED);
|
||||||
}
|
}
|
||||||
disconnect(true);
|
disconnect(true);
|
||||||
Log.d(Config.LOGTAG, account.getJid().toBareJid()+": could not register. url="+url);
|
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": could not register. url=" + url);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getWebRegistrationUrl() {
|
public String getWebRegistrationUrl() {
|
||||||
|
@ -1023,11 +1024,8 @@ public class XmppConnection implements Runnable {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendBindRequest() {
|
private void sendBindRequest() {
|
||||||
while(!mXmppConnectionService.areMessagesInitialized() && socket != null && !socket.isClosed()) {
|
while (!mXmppConnectionService.areMessagesInitialized() && socket != null && !socket.isClosed()) {
|
||||||
try {
|
uninterruptedSleep(500);
|
||||||
Thread.sleep(500);
|
|
||||||
} catch (final InterruptedException ignored) {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
needsBinding = false;
|
needsBinding = false;
|
||||||
clearIqCallbacks();
|
clearIqCallbacks();
|
||||||
|
@ -1046,7 +1044,7 @@ public class XmppConnection implements Runnable {
|
||||||
if (jid != null && jid.getContent() != null) {
|
if (jid != null && jid.getContent() != null) {
|
||||||
try {
|
try {
|
||||||
if (account.setJid(Jid.fromString(jid.getContent()))) {
|
if (account.setJid(Jid.fromString(jid.getContent()))) {
|
||||||
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": bare jid changed during bind. updating database");
|
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": bare jid changed during bind. updating database");
|
||||||
mXmppConnectionService.databaseBackend.updateAccount(account);
|
mXmppConnectionService.databaseBackend.updateAccount(account);
|
||||||
}
|
}
|
||||||
if (streamFeatures.hasChild("session")
|
if (streamFeatures.hasChild("session")
|
||||||
|
@ -1057,7 +1055,7 @@ public class XmppConnection implements Runnable {
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
} catch (final InvalidJidException e) {
|
} catch (final InvalidJidException e) {
|
||||||
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": server reported invalid jid ("+jid.getContent()+") on bind");
|
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": server reported invalid jid (" + jid.getContent() + ") on bind");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Log.d(Config.LOGTAG, account.getJid() + ": disconnecting because of bind failure. (no jid)");
|
Log.d(Config.LOGTAG, account.getJid() + ": disconnecting because of bind failure. (no jid)");
|
||||||
|
@ -1084,7 +1082,7 @@ public class XmppConnection implements Runnable {
|
||||||
if (this.packetCallbacks.size() == 0) {
|
if (this.packetCallbacks.size() == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": clearing "+this.packetCallbacks.size()+" iq callbacks");
|
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": clearing " + this.packetCallbacks.size() + " iq callbacks");
|
||||||
final Iterator<Pair<IqPacket, OnIqPacketReceived>> iterator = this.packetCallbacks.values().iterator();
|
final Iterator<Pair<IqPacket, OnIqPacketReceived>> iterator = this.packetCallbacks.values().iterator();
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
Pair<IqPacket, OnIqPacketReceived> entry = iterator.next();
|
Pair<IqPacket, OnIqPacketReceived> entry = iterator.next();
|
||||||
|
@ -1092,11 +1090,11 @@ public class XmppConnection implements Runnable {
|
||||||
iterator.remove();
|
iterator.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(OnIqPacketReceived callback : callbacks) {
|
for (OnIqPacketReceived callback : callbacks) {
|
||||||
try {
|
try {
|
||||||
callback.onIqPacketReceived(account, failurePacket);
|
callback.onIqPacketReceived(account, failurePacket);
|
||||||
} catch (StateChangingError error) {
|
} catch (StateChangingError error) {
|
||||||
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": caught StateChangingError("+error.state.toString()+") while clearing callbacks");
|
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": caught StateChangingError(" + error.state.toString() + ") while clearing callbacks");
|
||||||
//ignore
|
//ignore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1105,13 +1103,13 @@ public class XmppConnection implements Runnable {
|
||||||
|
|
||||||
public void sendDiscoTimeout() {
|
public void sendDiscoTimeout() {
|
||||||
if (mWaitForDisco.compareAndSet(true, false)) {
|
if (mWaitForDisco.compareAndSet(true, false)) {
|
||||||
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": finalizing bind after disco timeout");
|
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": finalizing bind after disco timeout");
|
||||||
finalizeBind();
|
finalizeBind();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendStartSession() {
|
private void sendStartSession() {
|
||||||
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": sending legacy session to outdated server");
|
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": sending legacy session to outdated server");
|
||||||
final IqPacket startSession = new IqPacket(IqPacket.TYPE.SET);
|
final IqPacket startSession = new IqPacket(IqPacket.TYPE.SET);
|
||||||
startSession.addChild("session", "urn:ietf:params:xml:ns:xmpp-session");
|
startSession.addChild("session", "urn:ietf:params:xml:ns:xmpp-session");
|
||||||
this.sendUnmodifiedIqPacket(startSession, new OnIqPacketReceived() {
|
this.sendUnmodifiedIqPacket(startSession, new OnIqPacketReceived() {
|
||||||
|
@ -1149,7 +1147,7 @@ public class XmppConnection implements Runnable {
|
||||||
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": starting service discovery");
|
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": starting service discovery");
|
||||||
mPendingServiceDiscoveries.set(0);
|
mPendingServiceDiscoveries.set(0);
|
||||||
if (smVersion == 0 || Patches.DISCO_EXCEPTIONS.contains(account.getJid().getDomainpart())) {
|
if (smVersion == 0 || Patches.DISCO_EXCEPTIONS.contains(account.getJid().getDomainpart())) {
|
||||||
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": do not wait for service discovery");
|
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": do not wait for service discovery");
|
||||||
mWaitForDisco.set(false);
|
mWaitForDisco.set(false);
|
||||||
} else {
|
} else {
|
||||||
mWaitForDisco.set(true);
|
mWaitForDisco.set(true);
|
||||||
|
@ -1166,7 +1164,7 @@ public class XmppConnection implements Runnable {
|
||||||
if (discoveryResult == null) {
|
if (discoveryResult == null) {
|
||||||
sendServiceDiscoveryInfo(account.getServer());
|
sendServiceDiscoveryInfo(account.getServer());
|
||||||
} else {
|
} else {
|
||||||
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": server caps came from cache");
|
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": server caps came from cache");
|
||||||
disco.put(account.getServer(), discoveryResult);
|
disco.put(account.getServer(), discoveryResult);
|
||||||
}
|
}
|
||||||
sendServiceDiscoveryInfo(account.getJid().toBareJid());
|
sendServiceDiscoveryInfo(account.getJid().toBareJid());
|
||||||
|
@ -1255,7 +1253,7 @@ public class XmppConnection implements Runnable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(Jid jid : items) {
|
for (Jid jid : items) {
|
||||||
sendServiceDiscoveryInfo(jid);
|
sendServiceDiscoveryInfo(jid);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -1291,7 +1289,7 @@ public class XmppConnection implements Runnable {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processStreamError(final Tag currentTag)
|
private void processStreamError(final Tag currentTag)
|
||||||
throws XmlPullParserException, IOException {
|
throws XmlPullParserException, IOException {
|
||||||
final Element streamError = tagReader.readElement(currentTag);
|
final Element streamError = tagReader.readElement(currentTag);
|
||||||
if (streamError == null) {
|
if (streamError == null) {
|
||||||
return;
|
return;
|
||||||
|
@ -1301,14 +1299,14 @@ public class XmppConnection implements Runnable {
|
||||||
account.setResource(resource + "." + nextRandomId());
|
account.setResource(resource + "." + nextRandomId());
|
||||||
Log.d(Config.LOGTAG,
|
Log.d(Config.LOGTAG,
|
||||||
account.getJid().toBareJid() + ": switching resource due to conflict ("
|
account.getJid().toBareJid() + ": switching resource due to conflict ("
|
||||||
+ account.getResource() + ")");
|
+ account.getResource() + ")");
|
||||||
throw new IOException();
|
throw new IOException();
|
||||||
} else if (streamError.hasChild("host-unknown")) {
|
} else if (streamError.hasChild("host-unknown")) {
|
||||||
throw new StateChangingException(Account.State.HOST_UNKNOWN);
|
throw new StateChangingException(Account.State.HOST_UNKNOWN);
|
||||||
} else if (streamError.hasChild("policy-violation")) {
|
} else if (streamError.hasChild("policy-violation")) {
|
||||||
throw new StateChangingException(Account.State.POLICY_VIOLATION);
|
throw new StateChangingException(Account.State.POLICY_VIOLATION);
|
||||||
} else {
|
} else {
|
||||||
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": stream error "+streamError.toString());
|
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": stream error " + streamError.toString());
|
||||||
throw new StateChangingException(Account.State.STREAM_ERROR);
|
throw new StateChangingException(Account.State.STREAM_ERROR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1324,7 +1322,7 @@ public class XmppConnection implements Runnable {
|
||||||
}
|
}
|
||||||
|
|
||||||
private String nextRandomId() {
|
private String nextRandomId() {
|
||||||
return CryptoHelper.random(50,mXmppConnectionService.getRNG());
|
return CryptoHelper.random(50, mXmppConnectionService.getRNG());
|
||||||
}
|
}
|
||||||
|
|
||||||
public String sendIqPacket(final IqPacket packet, final OnIqPacketReceived callback) {
|
public String sendIqPacket(final IqPacket packet, final OnIqPacketReceived callback) {
|
||||||
|
@ -1388,22 +1386,22 @@ public class XmppConnection implements Runnable {
|
||||||
public void setOnMessagePacketReceivedListener(
|
public void setOnMessagePacketReceivedListener(
|
||||||
final OnMessagePacketReceived listener) {
|
final OnMessagePacketReceived listener) {
|
||||||
this.messageListener = listener;
|
this.messageListener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setOnUnregisteredIqPacketReceivedListener(
|
public void setOnUnregisteredIqPacketReceivedListener(
|
||||||
final OnIqPacketReceived listener) {
|
final OnIqPacketReceived listener) {
|
||||||
this.unregisteredIqListener = listener;
|
this.unregisteredIqListener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setOnPresencePacketReceivedListener(
|
public void setOnPresencePacketReceivedListener(
|
||||||
final OnPresencePacketReceived listener) {
|
final OnPresencePacketReceived listener) {
|
||||||
this.presenceListener = listener;
|
this.presenceListener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setOnJinglePacketReceivedListener(
|
public void setOnJinglePacketReceivedListener(
|
||||||
final OnJinglePacketReceived listener) {
|
final OnJinglePacketReceived listener) {
|
||||||
this.jingleListener = listener;
|
this.jingleListener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setOnStatusChangedListener(final OnStatusChanged listener) {
|
public void setOnStatusChangedListener(final OnStatusChanged listener) {
|
||||||
this.statusListener = listener;
|
this.statusListener = listener;
|
||||||
|
@ -1428,10 +1426,10 @@ public class XmppConnection implements Runnable {
|
||||||
try {
|
try {
|
||||||
socket.close();
|
socket.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": io exception "+e.getMessage()+" during force close");
|
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": io exception " + e.getMessage() + " during force close");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": socket was null during force close");
|
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": socket was null during force close");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1441,41 +1439,47 @@ public class XmppConnection implements Runnable {
|
||||||
|
|
||||||
public void disconnect(final boolean force) {
|
public void disconnect(final boolean force) {
|
||||||
interrupt();
|
interrupt();
|
||||||
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": disconnecting force="+Boolean.valueOf(force));
|
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": disconnecting force=" + Boolean.toString(force));
|
||||||
if (force) {
|
if (force) {
|
||||||
forceCloseSocket();
|
forceCloseSocket();
|
||||||
} else {
|
} else {
|
||||||
if (tagWriter.isActive()) {
|
if (tagWriter.isActive()) {
|
||||||
tagWriter.finish();
|
tagWriter.finish();
|
||||||
|
final Socket currentSocket = socket;
|
||||||
try {
|
try {
|
||||||
int i = 0;
|
for (int i = 0; i <= 10 && !tagWriter.finished() && !currentSocket.isClosed(); ++i) {
|
||||||
boolean warned = false;
|
uninterruptedSleep(100);
|
||||||
while (!tagWriter.finished() && socket.isConnected() && i <= 10) {
|
|
||||||
if (!warned) {
|
|
||||||
Log.d(Config.LOGTAG, account.getJid().toBareJid()+": waiting for tag writer to finish");
|
|
||||||
warned = true;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
Thread.sleep(200);
|
|
||||||
} catch(InterruptedException e) {
|
|
||||||
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": sleep interrupted");
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
}
|
||||||
if (warned) {
|
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": closing stream");
|
||||||
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": tag writer has finished");
|
|
||||||
}
|
|
||||||
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": closing stream");
|
|
||||||
tagWriter.writeTag(Tag.end("stream:stream"));
|
tagWriter.writeTag(Tag.end("stream:stream"));
|
||||||
|
for (int i = 0; i <= 20 && !currentSocket.isClosed(); ++i) {
|
||||||
|
uninterruptedSleep(100);
|
||||||
|
}
|
||||||
|
if (currentSocket.isClosed()) {
|
||||||
|
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": remote closed socket");
|
||||||
|
} else {
|
||||||
|
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": remote has not closed socket. force closing");
|
||||||
|
}
|
||||||
} catch (final IOException e) {
|
} catch (final IOException e) {
|
||||||
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": io exception during disconnect ("+e.getMessage()+")");
|
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": io exception during disconnect (" + e.getMessage() + ")");
|
||||||
} finally {
|
} finally {
|
||||||
|
FileBackend.close(currentSocket);
|
||||||
forceCloseSocket();
|
forceCloseSocket();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
forceCloseSocket();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void uninterruptedSleep(int time) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(time);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
//ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void resetStreamId() {
|
public void resetStreamId() {
|
||||||
this.streamId = null;
|
this.streamId = null;
|
||||||
}
|
}
|
||||||
|
@ -1553,6 +1557,7 @@ public class XmppConnection implements Runnable {
|
||||||
public long getLastDiscoStarted() {
|
public long getLastDiscoStarted() {
|
||||||
return this.lastDiscoStarted;
|
return this.lastDiscoStarted;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getLastPacketReceived() {
|
public long getLastPacketReceived() {
|
||||||
return this.lastPacketReceived;
|
return this.lastPacketReceived;
|
||||||
}
|
}
|
||||||
|
@ -1717,10 +1722,10 @@ public class XmppConnection implements Runnable {
|
||||||
if (items.size() > 0) {
|
if (items.size() > 0) {
|
||||||
try {
|
try {
|
||||||
long maxsize = Long.parseLong(items.get(0).getValue().getExtendedDiscoInformation(Namespace.HTTP_UPLOAD, "max-file-size"));
|
long maxsize = Long.parseLong(items.get(0).getValue().getExtendedDiscoInformation(Namespace.HTTP_UPLOAD, "max-file-size"));
|
||||||
if(filesize <= maxsize) {
|
if (filesize <= maxsize) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": http upload is not available for files with size "+filesize+" (max is "+maxsize+")");
|
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": http upload is not available for files with size " + filesize + " (max is " + maxsize + ")");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -1734,15 +1739,15 @@ public class XmppConnection implements Runnable {
|
||||||
|
|
||||||
public long getMaxHttpUploadSize() {
|
public long getMaxHttpUploadSize() {
|
||||||
List<Entry<Jid, ServiceDiscoveryResult>> items = findDiscoItemsByFeature(Namespace.HTTP_UPLOAD);
|
List<Entry<Jid, ServiceDiscoveryResult>> items = findDiscoItemsByFeature(Namespace.HTTP_UPLOAD);
|
||||||
if (items.size() > 0) {
|
if (items.size() > 0) {
|
||||||
try {
|
try {
|
||||||
return Long.parseLong(items.get(0).getValue().getExtendedDiscoInformation(Namespace.HTTP_UPLOAD, "max-file-size"));
|
return Long.parseLong(items.get(0).getValue().getExtendedDiscoInformation(Namespace.HTTP_UPLOAD, "max-file-size"));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean stanzaIds() {
|
public boolean stanzaIds() {
|
||||||
|
|
Loading…
Reference in New Issue