implement see-other-host stream error
This commit is contained in:
parent
a40d244bf5
commit
5b2444ea13
|
@ -787,6 +787,7 @@ public class Account extends AbstractEntity implements AvatarService.Avatarable
|
||||||
BIND_FAILURE,
|
BIND_FAILURE,
|
||||||
HOST_UNKNOWN,
|
HOST_UNKNOWN,
|
||||||
STREAM_ERROR,
|
STREAM_ERROR,
|
||||||
|
SEE_OTHER_HOST,
|
||||||
STREAM_OPENING_ERROR,
|
STREAM_OPENING_ERROR,
|
||||||
POLICY_VIOLATION,
|
POLICY_VIOLATION,
|
||||||
PAYMENT_REQUIRED,
|
PAYMENT_REQUIRED,
|
||||||
|
@ -874,6 +875,8 @@ public class Account extends AbstractEntity implements AvatarService.Avatarable
|
||||||
return R.string.account_status_stream_opening_error;
|
return R.string.account_status_stream_opening_error;
|
||||||
case PAYMENT_REQUIRED:
|
case PAYMENT_REQUIRED:
|
||||||
return R.string.payment_required;
|
return R.string.payment_required;
|
||||||
|
case SEE_OTHER_HOST:
|
||||||
|
return R.string.reconnect_on_other_host;
|
||||||
case MISSING_INTERNET_PERMISSION:
|
case MISSING_INTERNET_PERMISSION:
|
||||||
return R.string.missing_internet_permission;
|
return R.string.missing_internet_permission;
|
||||||
case TEMPORARY_AUTH_FAILURE:
|
case TEMPORARY_AUTH_FAILURE:
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package eu.siacs.conversations.utils;
|
package eu.siacs.conversations.utils;
|
||||||
|
|
||||||
|
import com.google.common.net.InetAddresses;
|
||||||
|
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
public class IP {
|
public class IP {
|
||||||
|
@ -27,4 +29,14 @@ public class IP {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String unwrapIPv6(final String host) {
|
||||||
|
if (host.length() > 2 && host.charAt(0) == '[' && host.charAt(host.length() - 1) == ']') {
|
||||||
|
final String ip = host.substring(1,host.length() -1);
|
||||||
|
if (InetAddresses.isInetAddress(ip)) {
|
||||||
|
return ip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,10 @@ import android.util.Log;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import com.google.common.base.Strings;
|
||||||
import com.google.common.base.Throwables;
|
import com.google.common.base.Throwables;
|
||||||
|
import com.google.common.net.InetAddresses;
|
||||||
|
import com.google.common.primitives.Ints;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
@ -446,6 +449,65 @@ public class Resolver {
|
||||||
contentValues.put(AUTHENTICATED, authenticated ? 1 : 0);
|
contentValues.put(AUTHENTICATED, authenticated ? 1 : 0);
|
||||||
return contentValues;
|
return contentValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Result seeOtherHost(final String seeOtherHost) {
|
||||||
|
final String hostname = seeOtherHost.trim();
|
||||||
|
if (hostname.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
final Result result = new Result();
|
||||||
|
result.directTls = this.directTls;
|
||||||
|
final int portSegmentStart = hostname.lastIndexOf(':');
|
||||||
|
if (hostname.charAt(hostname.length() - 1) != ']'
|
||||||
|
&& portSegmentStart >= 0
|
||||||
|
&& hostname.length() >= portSegmentStart + 1) {
|
||||||
|
final String hostPart = hostname.substring(0, portSegmentStart);
|
||||||
|
final String portPart = hostname.substring(portSegmentStart + 1);
|
||||||
|
final Integer port = Ints.tryParse(portPart);
|
||||||
|
if (port == null || Strings.isNullOrEmpty(hostPart)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
final String host = eu.siacs.conversations.utils.IP.unwrapIPv6(hostPart);
|
||||||
|
result.port = port;
|
||||||
|
if (InetAddresses.isInetAddress(host)) {
|
||||||
|
final InetAddress inetAddress;
|
||||||
|
try {
|
||||||
|
inetAddress = InetAddresses.forString(host);
|
||||||
|
} catch (final IllegalArgumentException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
result.ip = inetAddress;
|
||||||
|
} else {
|
||||||
|
if (hostPart.trim().isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
result.hostname = DNSName.from(hostPart.trim());
|
||||||
|
} catch (final Exception e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
final String host = eu.siacs.conversations.utils.IP.unwrapIPv6(hostname);
|
||||||
|
if (InetAddresses.isInetAddress(host)) {
|
||||||
|
final InetAddress inetAddress;
|
||||||
|
try {
|
||||||
|
inetAddress = InetAddresses.forString(host);
|
||||||
|
} catch (final IllegalArgumentException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
result.ip = inetAddress;
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
result.hostname = DNSName.from(hostname);
|
||||||
|
} catch (final Exception e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.port = port;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -189,6 +189,8 @@ public class XmppConnection implements Runnable {
|
||||||
private HashedToken.Mechanism hashTokenRequest;
|
private HashedToken.Mechanism hashTokenRequest;
|
||||||
private HttpUrl redirectionUrl = null;
|
private HttpUrl redirectionUrl = null;
|
||||||
private String verifiedHostname = null;
|
private String verifiedHostname = null;
|
||||||
|
private Resolver.Result currentResolverResult;
|
||||||
|
private Resolver.Result seeOtherHostResolverResult;
|
||||||
private volatile Thread mThread;
|
private volatile Thread mThread;
|
||||||
private CountDownLatch mStreamCountDownLatch;
|
private CountDownLatch mStreamCountDownLatch;
|
||||||
|
|
||||||
|
@ -360,7 +362,12 @@ public class XmppConnection implements Runnable {
|
||||||
+ storedBackupResult);
|
+ storedBackupResult);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (Iterator<Resolver.Result> iterator = results.iterator();
|
final Resolver.Result seeOtherHost = this.seeOtherHostResolverResult;
|
||||||
|
if (seeOtherHost != null) {
|
||||||
|
Log.d(Config.LOGTAG,account.getJid().asBareJid()+": injected see-other-host on position 0");
|
||||||
|
results.add(0, seeOtherHost);
|
||||||
|
}
|
||||||
|
for (final Iterator<Resolver.Result> iterator = results.iterator();
|
||||||
iterator.hasNext(); ) {
|
iterator.hasNext(); ) {
|
||||||
final Resolver.Result result = iterator.next();
|
final Resolver.Result result = iterator.next();
|
||||||
if (Thread.currentThread().isInterrupted()) {
|
if (Thread.currentThread().isInterrupted()) {
|
||||||
|
@ -374,7 +381,6 @@ public class XmppConnection implements Runnable {
|
||||||
features.encryptionEnabled = result.isDirectTls();
|
features.encryptionEnabled = result.isDirectTls();
|
||||||
verifiedHostname =
|
verifiedHostname =
|
||||||
result.isAuthenticated() ? result.getHostname().toString() : null;
|
result.isAuthenticated() ? result.getHostname().toString() : null;
|
||||||
Log.d(Config.LOGTAG, "verified hostname " + verifiedHostname);
|
|
||||||
final InetSocketAddress addr;
|
final InetSocketAddress addr;
|
||||||
if (result.getIp() != null) {
|
if (result.getIp() != null) {
|
||||||
addr = new InetSocketAddress(result.getIp(), result.getPort());
|
addr = new InetSocketAddress(result.getIp(), result.getPort());
|
||||||
|
@ -422,6 +428,8 @@ public class XmppConnection implements Runnable {
|
||||||
mXmppConnectionService.databaseBackend.saveResolverResult(
|
mXmppConnectionService.databaseBackend.saveResolverResult(
|
||||||
domain, result);
|
domain, result);
|
||||||
}
|
}
|
||||||
|
this.currentResolverResult = result;
|
||||||
|
this.seeOtherHostResolverResult = null;
|
||||||
break; // successfully connected to server that speaks xmpp
|
break; // successfully connected to server that speaks xmpp
|
||||||
} else {
|
} else {
|
||||||
FileBackend.close(localSocket);
|
FileBackend.close(localSocket);
|
||||||
|
@ -2166,6 +2174,21 @@ public class XmppConnection implements Runnable {
|
||||||
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": policy violation. " + text);
|
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": policy violation. " + text);
|
||||||
failPendingMessages(text);
|
failPendingMessages(text);
|
||||||
throw new StateChangingException(Account.State.POLICY_VIOLATION);
|
throw new StateChangingException(Account.State.POLICY_VIOLATION);
|
||||||
|
} else if (streamError.hasChild("see-other-host")) {
|
||||||
|
final String seeOtherHost = streamError.findChildContent("see-other-host");
|
||||||
|
final Resolver.Result currentResolverResult = this.currentResolverResult;
|
||||||
|
if (Strings.isNullOrEmpty(seeOtherHost) || currentResolverResult == null) {
|
||||||
|
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": stream error " + streamError);
|
||||||
|
throw new StateChangingException(Account.State.STREAM_ERROR);
|
||||||
|
}
|
||||||
|
Log.d(Config.LOGTAG,account.getJid().asBareJid()+": see other host: "+seeOtherHost+" "+currentResolverResult);
|
||||||
|
final Resolver.Result seeOtherResult = currentResolverResult.seeOtherHost(seeOtherHost);
|
||||||
|
if (seeOtherResult != null) {
|
||||||
|
this.seeOtherHostResolverResult = seeOtherResult;
|
||||||
|
throw new StateChangingException(Account.State.SEE_OTHER_HOST);
|
||||||
|
} else {
|
||||||
|
throw new StateChangingException(Account.State.STREAM_ERROR);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": stream error " + streamError);
|
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": stream error " + streamError);
|
||||||
throw new StateChangingException(Account.State.STREAM_ERROR);
|
throw new StateChangingException(Account.State.STREAM_ERROR);
|
||||||
|
|
|
@ -553,13 +553,13 @@ public class JingleRtpConnection extends AbstractJingleConnection
|
||||||
sendSessionTerminate(Reason.FAILED_APPLICATION, cause.getMessage());
|
sendSessionTerminate(Reason.FAILED_APPLICATION, cause.getMessage());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
processCandidates(receivedContentAccept.contents.entrySet());
|
|
||||||
updateEndUserState();
|
|
||||||
Log.d(
|
Log.d(
|
||||||
Config.LOGTAG,
|
Config.LOGTAG,
|
||||||
id.getAccount().getJid().asBareJid()
|
id.getAccount().getJid().asBareJid()
|
||||||
+ ": remote has accepted content-add "
|
+ ": remote has accepted content-add "
|
||||||
+ ContentAddition.summary(receivedContentAccept));
|
+ ContentAddition.summary(receivedContentAccept));
|
||||||
|
processCandidates(receivedContentAccept.contents.entrySet());
|
||||||
|
updateEndUserState();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void receiveContentModify(final JinglePacket jinglePacket) {
|
private void receiveContentModify(final JinglePacket jinglePacket) {
|
||||||
|
|
|
@ -587,6 +587,7 @@
|
||||||
<string name="type_web">Web browser</string>
|
<string name="type_web">Web browser</string>
|
||||||
<string name="type_console">Console</string>
|
<string name="type_console">Console</string>
|
||||||
<string name="payment_required">Payment required</string>
|
<string name="payment_required">Payment required</string>
|
||||||
|
<string name="reconnect_on_other_host">Reconnect on other host</string>
|
||||||
<string name="missing_internet_permission">Grant permission to use the Internet</string>
|
<string name="missing_internet_permission">Grant permission to use the Internet</string>
|
||||||
<string name="me">Me</string>
|
<string name="me">Me</string>
|
||||||
<string name="contact_asks_for_presence_subscription">Contact asks for presence subscription</string>
|
<string name="contact_asks_for_presence_subscription">Contact asks for presence subscription</string>
|
||||||
|
|
Loading…
Reference in a new issue