order canditates by priority before attempting to connect

Daniel Gultsch created

Change summary

src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java      |  12 
src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java | 346 
2 files changed, 180 insertions(+), 178 deletions(-)

Detailed changes

src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java 🔗

@@ -11,6 +11,7 @@ import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map.Entry;
@@ -303,7 +304,7 @@ public class JingleConnection implements Transferable {
         if (this.initialTransport == Transport.IBB) {
             this.sendInitRequest();
         } else if (this.candidates.size() > 0) {
-            this.sendInitRequest();
+            this.sendInitRequest(); //TODO we will never get here? Can probably be removed
         } else {
             this.mJingleConnectionManager.getPrimaryCandidate(account, (success, candidate) -> {
                 if (success) {
@@ -635,7 +636,7 @@ public class JingleConnection implements Transferable {
 
     private boolean receiveAccept(JinglePacket packet) {
         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;
         }
         this.mJingleStatus = JINGLE_STATUS_ACCEPTED;
@@ -654,7 +655,7 @@ public class JingleConnection implements Transferable {
                         this.ibbBlockSize = bs;
                     }
                 } 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);
@@ -850,7 +851,7 @@ public class JingleConnection implements Transferable {
                     this.ibbBlockSize = bs;
                 }
             } 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();
@@ -889,7 +890,7 @@ public class JingleConnection implements Transferable {
                         this.ibbBlockSize = bs;
                     }
                 } 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);
@@ -1087,6 +1088,7 @@ public class JingleConnection implements Transferable {
     }
 
     private void mergeCandidates(List<JingleCandidate> candidates) {
+        Collections.sort(candidates, (a, b) -> Integer.compare(b.getPriority(), a.getPriority()));
         for (JingleCandidate c : candidates) {
             mergeCandidate(c);
         }

src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java 🔗

@@ -22,177 +22,177 @@ import eu.siacs.conversations.utils.WakeLockHelper;
 import eu.siacs.conversations.xmpp.jingle.stanzas.Content;
 
 public class JingleSocks5Transport extends JingleTransport {
-	private JingleCandidate candidate;
-	private JingleConnection connection;
-	private String destination;
-	private OutputStream outputStream;
-	private InputStream inputStream;
-	private boolean isEstablished = false;
-	private boolean activated = false;
-	private Socket socket;
-
-	JingleSocks5Transport(JingleConnection jingleConnection, JingleCandidate candidate) {
-		this.candidate = candidate;
-		this.connection = jingleConnection;
-		try {
-			MessageDigest mDigest = MessageDigest.getInstance("SHA-1");
-			StringBuilder destBuilder = new StringBuilder();
-			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");
-				destBuilder.append(jingleConnection.getSessionId());
-			} else {
-				destBuilder.append(jingleConnection.getTransportId());
-			}
-			if (candidate.isOurs()) {
-				destBuilder.append(jingleConnection.getAccount().getJid());
-				destBuilder.append(jingleConnection.getCounterPart());
-			} else {
-				destBuilder.append(jingleConnection.getCounterPart());
-				destBuilder.append(jingleConnection.getAccount().getJid());
-			}
-			mDigest.reset();
-			this.destination = CryptoHelper.bytesToHex(mDigest
-					.digest(destBuilder.toString().getBytes()));
-		} catch (NoSuchAlgorithmException e) {
-
-		}
-	}
-
-	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 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 boolean isProxy() {
-		return this.candidate.getType() == JingleCandidate.TYPE_PROXY;
-	}
-
-	public boolean needsActivation() {
-		return (this.isProxy() && !this.activated);
-	}
-
-	public void disconnect() {
-		FileBackend.close(inputStream);
-		FileBackend.close(outputStream);
-		FileBackend.close(socket);
-	}
-
-	public boolean isEstablished() {
-		return this.isEstablished;
-	}
-
-	public JingleCandidate getCandidate() {
-		return this.candidate;
-	}
-
-	public void setActivated(boolean activated) {
-		this.activated = activated;
-	}
+    private final JingleCandidate candidate;
+    private final JingleConnection connection;
+    private final String destination;
+    private OutputStream outputStream;
+    private InputStream inputStream;
+    private boolean isEstablished = false;
+    private boolean activated = false;
+    private Socket socket;
+
+    JingleSocks5Transport(JingleConnection jingleConnection, JingleCandidate candidate) {
+        final MessageDigest messageDigest;
+        try {
+            messageDigest = MessageDigest.getInstance("SHA-1");
+        } catch (NoSuchAlgorithmException e) {
+            throw new AssertionError(e);
+        }
+        this.candidate = candidate;
+        this.connection = jingleConnection;
+        final StringBuilder destBuilder = new StringBuilder();
+        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");
+            destBuilder.append(jingleConnection.getSessionId());
+        } else {
+            destBuilder.append(jingleConnection.getTransportId());
+        }
+        if (candidate.isOurs()) {
+            destBuilder.append(jingleConnection.getAccount().getJid());
+            destBuilder.append(jingleConnection.getCounterPart());
+        } else {
+            destBuilder.append(jingleConnection.getCounterPart());
+            destBuilder.append(jingleConnection.getAccount().getJid());
+        }
+        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 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 boolean isProxy() {
+        return this.candidate.getType() == JingleCandidate.TYPE_PROXY;
+    }
+
+    public boolean needsActivation() {
+        return (this.isProxy() && !this.activated);
+    }
+
+    public void disconnect() {
+        FileBackend.close(inputStream);
+        FileBackend.close(outputStream);
+        FileBackend.close(socket);
+    }
+
+    public boolean isEstablished() {
+        return this.isEstablished;
+    }
+
+    public JingleCandidate getCandidate() {
+        return this.candidate;
+    }
+
+    public void setActivated(boolean activated) {
+        this.activated = activated;
+    }
 }