order canditates by priority before attempting to connect

This commit is contained in:
Daniel Gultsch 2019-09-01 11:34:36 +02:00
parent 7d6bd540d9
commit 783ed53d3a
2 changed files with 168 additions and 166 deletions

View file

@ -11,6 +11,7 @@ import java.io.OutputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map.Entry; import java.util.Map.Entry;
@ -303,7 +304,7 @@ public class JingleConnection implements Transferable {
if (this.initialTransport == Transport.IBB) { if (this.initialTransport == Transport.IBB) {
this.sendInitRequest(); this.sendInitRequest();
} else if (this.candidates.size() > 0) { } else if (this.candidates.size() > 0) {
this.sendInitRequest(); this.sendInitRequest(); //TODO we will never get here? Can probably be removed
} else { } else {
this.mJingleConnectionManager.getPrimaryCandidate(account, (success, candidate) -> { this.mJingleConnectionManager.getPrimaryCandidate(account, (success, candidate) -> {
if (success) { if (success) {
@ -635,7 +636,7 @@ public class JingleConnection implements Transferable {
private boolean receiveAccept(JinglePacket packet) { private boolean receiveAccept(JinglePacket packet) {
if (this.mJingleStatus != JINGLE_STATUS_INITIATED) { if (this.mJingleStatus != JINGLE_STATUS_INITIATED) {
Log.d(Config.LOGTAG,account.getJid().asBareJid()+": received out of order session-accept"); Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": received out of order session-accept");
return false; return false;
} }
this.mJingleStatus = JINGLE_STATUS_ACCEPTED; this.mJingleStatus = JINGLE_STATUS_ACCEPTED;
@ -654,7 +655,7 @@ public class JingleConnection implements Transferable {
this.ibbBlockSize = bs; this.ibbBlockSize = bs;
} }
} catch (Exception e) { } catch (Exception e) {
Log.d(Config.LOGTAG,account.getJid().asBareJid()+": unable to parse block size in session-accept"); Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": unable to parse block size in session-accept");
} }
} }
this.transport = new JingleInbandTransport(this, this.transportId, this.ibbBlockSize); this.transport = new JingleInbandTransport(this, this.transportId, this.ibbBlockSize);
@ -850,7 +851,7 @@ public class JingleConnection implements Transferable {
this.ibbBlockSize = bs; this.ibbBlockSize = bs;
} }
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
Log.d(Config.LOGTAG,account.getJid().asBareJid()+": unable to parse block size in transport-replace"); Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": unable to parse block size in transport-replace");
} }
} }
this.transportId = packet.getJingleContent().getTransportId(); this.transportId = packet.getJingleContent().getTransportId();
@ -889,7 +890,7 @@ public class JingleConnection implements Transferable {
this.ibbBlockSize = bs; this.ibbBlockSize = bs;
} }
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
Log.d(Config.LOGTAG, account.getJid().asBareJid()+": unable to parse block size in transport-accept"); Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": unable to parse block size in transport-accept");
} }
} }
this.transport = new JingleInbandTransport(this, this.transportId, this.ibbBlockSize); this.transport = new JingleInbandTransport(this, this.transportId, this.ibbBlockSize);
@ -1087,6 +1088,7 @@ public class JingleConnection implements Transferable {
} }
private void mergeCandidates(List<JingleCandidate> candidates) { private void mergeCandidates(List<JingleCandidate> candidates) {
Collections.sort(candidates, (a, b) -> Integer.compare(b.getPriority(), a.getPriority()));
for (JingleCandidate c : candidates) { for (JingleCandidate c : candidates) {
mergeCandidate(c); mergeCandidate(c);
} }

View file

@ -22,177 +22,177 @@ import eu.siacs.conversations.utils.WakeLockHelper;
import eu.siacs.conversations.xmpp.jingle.stanzas.Content; import eu.siacs.conversations.xmpp.jingle.stanzas.Content;
public class JingleSocks5Transport extends JingleTransport { public class JingleSocks5Transport extends JingleTransport {
private JingleCandidate candidate; private final JingleCandidate candidate;
private JingleConnection connection; private final JingleConnection connection;
private String destination; private final String destination;
private OutputStream outputStream; private OutputStream outputStream;
private InputStream inputStream; private InputStream inputStream;
private boolean isEstablished = false; private boolean isEstablished = false;
private boolean activated = false; private boolean activated = false;
private Socket socket; private Socket socket;
JingleSocks5Transport(JingleConnection jingleConnection, JingleCandidate candidate) { JingleSocks5Transport(JingleConnection jingleConnection, JingleCandidate candidate) {
this.candidate = candidate; final MessageDigest messageDigest;
this.connection = jingleConnection; try {
try { messageDigest = MessageDigest.getInstance("SHA-1");
MessageDigest mDigest = MessageDigest.getInstance("SHA-1"); } catch (NoSuchAlgorithmException e) {
StringBuilder destBuilder = new StringBuilder(); throw new AssertionError(e);
if (jingleConnection.getFtVersion() == Content.Version.FT_3) { }
Log.d(Config.LOGTAG, this.connection.getAccount().getJid().asBareJid() + ": using session Id instead of transport Id for proxy destination"); this.candidate = candidate;
destBuilder.append(jingleConnection.getSessionId()); this.connection = jingleConnection;
} else { final StringBuilder destBuilder = new StringBuilder();
destBuilder.append(jingleConnection.getTransportId()); if (jingleConnection.getFtVersion() == Content.Version.FT_3) {
} Log.d(Config.LOGTAG, this.connection.getAccount().getJid().asBareJid() + ": using session Id instead of transport Id for proxy destination");
if (candidate.isOurs()) { destBuilder.append(jingleConnection.getSessionId());
destBuilder.append(jingleConnection.getAccount().getJid()); } else {
destBuilder.append(jingleConnection.getCounterPart()); destBuilder.append(jingleConnection.getTransportId());
} else { }
destBuilder.append(jingleConnection.getCounterPart()); if (candidate.isOurs()) {
destBuilder.append(jingleConnection.getAccount().getJid()); destBuilder.append(jingleConnection.getAccount().getJid());
} destBuilder.append(jingleConnection.getCounterPart());
mDigest.reset(); } else {
this.destination = CryptoHelper.bytesToHex(mDigest destBuilder.append(jingleConnection.getCounterPart());
.digest(destBuilder.toString().getBytes())); destBuilder.append(jingleConnection.getAccount().getJid());
} catch (NoSuchAlgorithmException e) { }
messageDigest.reset();
this.destination = CryptoHelper.bytesToHex(messageDigest.digest(destBuilder.toString().getBytes()));
}
} public void connect(final OnTransportConnected callback) {
} new Thread(() -> {
try {
final boolean useTor = connection.getAccount().isOnion() || connection.getConnectionManager().getXmppConnectionService().useTorToConnect();
if (useTor) {
socket = SocksSocketFactory.createSocketOverTor(candidate.getHost(), candidate.getPort());
} else {
socket = new Socket();
SocketAddress address = new InetSocketAddress(candidate.getHost(), candidate.getPort());
socket.connect(address, Config.SOCKET_TIMEOUT * 1000);
}
inputStream = socket.getInputStream();
outputStream = socket.getOutputStream();
SocksSocketFactory.createSocksConnection(socket, destination, 0);
isEstablished = true;
callback.established();
} catch (IOException e) {
callback.failed();
}
}).start();
public void connect(final OnTransportConnected callback) { }
new Thread(() -> {
try {
final boolean useTor = connection.getAccount().isOnion() || connection.getConnectionManager().getXmppConnectionService().useTorToConnect();
if (useTor) {
socket = SocksSocketFactory.createSocketOverTor(candidate.getHost(), candidate.getPort());
} else {
socket = new Socket();
SocketAddress address = new InetSocketAddress(candidate.getHost(), candidate.getPort());
socket.connect(address, Config.SOCKET_TIMEOUT * 1000);
}
inputStream = socket.getInputStream();
outputStream = socket.getOutputStream();
SocksSocketFactory.createSocksConnection(socket, destination, 0);
isEstablished = true;
callback.established();
} catch (IOException e) {
callback.failed();
}
}).start();
} public void send(final DownloadableFile file, final OnFileTransmissionStatusChanged callback) {
new Thread(() -> {
InputStream fileInputStream = null;
final PowerManager.WakeLock wakeLock = connection.getConnectionManager().createWakeLock("jingle_send_" + connection.getSessionId());
try {
wakeLock.acquire();
MessageDigest digest = MessageDigest.getInstance("SHA-1");
digest.reset();
fileInputStream = connection.getFileInputStream();
if (fileInputStream == null) {
Log.d(Config.LOGTAG, connection.getAccount().getJid().asBareJid() + ": could not create input stream");
callback.onFileTransferAborted();
return;
}
final InputStream innerInputStream = AbstractConnectionManager.upgrade(file, fileInputStream);
long size = file.getExpectedSize();
long transmitted = 0;
int count;
byte[] buffer = new byte[8192];
while ((count = innerInputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, count);
digest.update(buffer, 0, count);
transmitted += count;
connection.updateProgress((int) ((((double) transmitted) / size) * 100));
}
outputStream.flush();
file.setSha1Sum(digest.digest());
if (callback != null) {
callback.onFileTransmitted(file);
}
} catch (Exception e) {
Log.d(Config.LOGTAG, connection.getAccount().getJid().asBareJid() + ": " + e.getMessage());
callback.onFileTransferAborted();
} finally {
FileBackend.close(fileInputStream);
WakeLockHelper.release(wakeLock);
}
}).start();
public void send(final DownloadableFile file, final OnFileTransmissionStatusChanged callback) { }
new Thread(() -> {
InputStream fileInputStream = null;
final PowerManager.WakeLock wakeLock = connection.getConnectionManager().createWakeLock("jingle_send_" + connection.getSessionId());
try {
wakeLock.acquire();
MessageDigest digest = MessageDigest.getInstance("SHA-1");
digest.reset();
fileInputStream = connection.getFileInputStream();
if (fileInputStream == null) {
Log.d(Config.LOGTAG, connection.getAccount().getJid().asBareJid() + ": could not create input stream");
callback.onFileTransferAborted();
return;
}
final InputStream innerInputStream = AbstractConnectionManager.upgrade(file, fileInputStream);
long size = file.getExpectedSize();
long transmitted = 0;
int count;
byte[] buffer = new byte[8192];
while ((count = innerInputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, count);
digest.update(buffer, 0, count);
transmitted += count;
connection.updateProgress((int) ((((double) transmitted) / size) * 100));
}
outputStream.flush();
file.setSha1Sum(digest.digest());
if (callback != null) {
callback.onFileTransmitted(file);
}
} catch (Exception e) {
Log.d(Config.LOGTAG, connection.getAccount().getJid().asBareJid() + ": " + e.getMessage());
callback.onFileTransferAborted();
} finally {
FileBackend.close(fileInputStream);
WakeLockHelper.release(wakeLock);
}
}).start();
} public void receive(final DownloadableFile file, final OnFileTransmissionStatusChanged callback) {
new Thread(() -> {
OutputStream fileOutputStream = null;
final PowerManager.WakeLock wakeLock = connection.getConnectionManager().createWakeLock("jingle_receive_" + connection.getSessionId());
try {
wakeLock.acquire();
MessageDigest digest = MessageDigest.getInstance("SHA-1");
digest.reset();
//inputStream.skip(45);
socket.setSoTimeout(30000);
fileOutputStream = connection.getFileOutputStream();
if (fileOutputStream == null) {
callback.onFileTransferAborted();
Log.d(Config.LOGTAG, connection.getAccount().getJid().asBareJid() + ": could not create output stream");
return;
}
double size = file.getExpectedSize();
long remainingSize = file.getExpectedSize();
byte[] buffer = new byte[8192];
int count;
while (remainingSize > 0) {
count = inputStream.read(buffer);
if (count == -1) {
callback.onFileTransferAborted();
Log.d(Config.LOGTAG, connection.getAccount().getJid().asBareJid() + ": file ended prematurely with " + remainingSize + " bytes remaining");
return;
} else {
fileOutputStream.write(buffer, 0, count);
digest.update(buffer, 0, count);
remainingSize -= count;
}
connection.updateProgress((int) (((size - remainingSize) / size) * 100));
}
fileOutputStream.flush();
fileOutputStream.close();
file.setSha1Sum(digest.digest());
callback.onFileTransmitted(file);
} catch (Exception e) {
Log.d(Config.LOGTAG, connection.getAccount().getJid().asBareJid() + ": " + e.getMessage());
callback.onFileTransferAborted();
} finally {
WakeLockHelper.release(wakeLock);
FileBackend.close(fileOutputStream);
FileBackend.close(inputStream);
}
}).start();
}
public void receive(final DownloadableFile file, final OnFileTransmissionStatusChanged callback) { public boolean isProxy() {
new Thread(() -> { return this.candidate.getType() == JingleCandidate.TYPE_PROXY;
OutputStream fileOutputStream = null; }
final PowerManager.WakeLock wakeLock = connection.getConnectionManager().createWakeLock("jingle_receive_" + connection.getSessionId());
try {
wakeLock.acquire();
MessageDigest digest = MessageDigest.getInstance("SHA-1");
digest.reset();
//inputStream.skip(45);
socket.setSoTimeout(30000);
fileOutputStream = connection.getFileOutputStream();
if (fileOutputStream == null) {
callback.onFileTransferAborted();
Log.d(Config.LOGTAG, connection.getAccount().getJid().asBareJid() + ": could not create output stream");
return;
}
double size = file.getExpectedSize();
long remainingSize = file.getExpectedSize();
byte[] buffer = new byte[8192];
int count;
while (remainingSize > 0) {
count = inputStream.read(buffer);
if (count == -1) {
callback.onFileTransferAborted();
Log.d(Config.LOGTAG, connection.getAccount().getJid().asBareJid() + ": file ended prematurely with " + remainingSize + " bytes remaining");
return;
} else {
fileOutputStream.write(buffer, 0, count);
digest.update(buffer, 0, count);
remainingSize -= count;
}
connection.updateProgress((int) (((size - remainingSize) / size) * 100));
}
fileOutputStream.flush();
fileOutputStream.close();
file.setSha1Sum(digest.digest());
callback.onFileTransmitted(file);
} catch (Exception e) {
Log.d(Config.LOGTAG, connection.getAccount().getJid().asBareJid() + ": " + e.getMessage());
callback.onFileTransferAborted();
} finally {
WakeLockHelper.release(wakeLock);
FileBackend.close(fileOutputStream);
FileBackend.close(inputStream);
}
}).start();
}
public boolean isProxy() { public boolean needsActivation() {
return this.candidate.getType() == JingleCandidate.TYPE_PROXY; return (this.isProxy() && !this.activated);
} }
public boolean needsActivation() { public void disconnect() {
return (this.isProxy() && !this.activated); FileBackend.close(inputStream);
} FileBackend.close(outputStream);
FileBackend.close(socket);
}
public void disconnect() { public boolean isEstablished() {
FileBackend.close(inputStream); return this.isEstablished;
FileBackend.close(outputStream); }
FileBackend.close(socket);
}
public boolean isEstablished() { public JingleCandidate getCandidate() {
return this.isEstablished; return this.candidate;
} }
public JingleCandidate getCandidate() { public void setActivated(boolean activated) {
return this.candidate; this.activated = activated;
} }
public void setActivated(boolean activated) {
this.activated = activated;
}
} }