From 963ddd11c214b64e0c8138fc0deeedfbc7dc60f1 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Thu, 2 Apr 2020 10:59:25 +0200 Subject: [PATCH] refactor jingle code to use objects for TransportInfo --- .../eu/siacs/conversations/xml/Namespace.java | 1 + .../xmpp/jingle/JingleCandidate.java | 28 +-- .../jingle/JingleFileTransferConnection.java | 199 ++++++++---------- .../conversations/xmpp/jingle/Transport.java | 5 - .../xmpp/jingle/stanzas/Content.java | 54 ++--- .../jingle/stanzas/GenericDescription.java | 2 +- .../jingle/stanzas/GenericTransportInfo.java | 20 ++ .../xmpp/jingle/stanzas/IbbTransportInfo.java | 46 ++++ .../jingle/stanzas/IceUdpTransportInfo.java | 22 ++ .../xmpp/jingle/stanzas/S5BTransportInfo.java | 50 +++++ 10 files changed, 263 insertions(+), 164 deletions(-) delete mode 100644 src/main/java/eu/siacs/conversations/xmpp/jingle/Transport.java create mode 100644 src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/GenericTransportInfo.java create mode 100644 src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/IbbTransportInfo.java create mode 100644 src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/IceUdpTransportInfo.java create mode 100644 src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/S5BTransportInfo.java diff --git a/src/main/java/eu/siacs/conversations/xml/Namespace.java b/src/main/java/eu/siacs/conversations/xml/Namespace.java index 6d4447e38..755de7fa5 100644 --- a/src/main/java/eu/siacs/conversations/xml/Namespace.java +++ b/src/main/java/eu/siacs/conversations/xml/Namespace.java @@ -29,6 +29,7 @@ public final class Namespace { public static final String AVATAR_CONVERSION = "urn:xmpp:pep-vcard-conversion:0"; public static final String JINGLE_TRANSPORTS_S5B = "urn:xmpp:jingle:transports:s5b:1"; public static final String JINGLE_TRANSPORTS_IBB = "urn:xmpp:jingle:transports:ibb:1"; + public static final String JINGLE_TRANSPORT_ICE_UDP = "urn:xmpp:jingle:transports:ice-udp:1"; public static final String IBB = "http://jabber.org/protocol/ibb"; public static final String PING = "urn:xmpp:ping"; public static final String PUSH = "urn:xmpp:push:0"; diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleCandidate.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleCandidate.java index 7415c32aa..e1f4db4b0 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleCandidate.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleCandidate.java @@ -101,22 +101,24 @@ public class JingleCandidate { return this.type; } - public static List parse(List canditates) { - List parsedCandidates = new ArrayList<>(); - for (Element c : canditates) { - parsedCandidates.add(JingleCandidate.parse(c)); + public static List parse(final List elements) { + final List candidates = new ArrayList<>(); + for (final Element element : elements) { + if ("candidate".equals(element.getName())) { + candidates.add(JingleCandidate.parse(element)); + } } - return parsedCandidates; + return candidates; } - public static JingleCandidate parse(Element candidate) { - JingleCandidate parsedCandidate = new JingleCandidate(candidate.getAttribute("cid"), false); - parsedCandidate.setHost(candidate.getAttribute("host")); - parsedCandidate.setJid(InvalidJid.getNullForInvalid(candidate.getAttributeAsJid("jid"))); - parsedCandidate.setType(candidate.getAttribute("type")); - parsedCandidate.setPriority(Integer.parseInt(candidate.getAttribute("priority"))); - parsedCandidate.setPort(Integer.parseInt(candidate.getAttribute("port"))); - return parsedCandidate; + public static JingleCandidate parse(Element element) { + final JingleCandidate candidate = new JingleCandidate(element.getAttribute("cid"), false); + candidate.setHost(element.getAttribute("host")); + candidate.setJid(InvalidJid.getNullForInvalid(element.getAttributeAsJid("jid"))); + candidate.setType(element.getAttribute("type")); + candidate.setPriority(Integer.parseInt(element.getAttribute("priority"))); + candidate.setPort(Integer.parseInt(element.getAttribute("port"))); + return candidate; } public Element toElement() { diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleFileTransferConnection.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleFileTransferConnection.java index 997f84b89..97d6a248f 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleFileTransferConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleFileTransferConnection.java @@ -4,6 +4,11 @@ import android.util.Base64; import android.util.Log; import com.google.common.base.Preconditions; +import com.google.common.base.Predicate; +import com.google.common.collect.Collections2; +import com.google.common.collect.Lists; + +import org.checkerframework.checker.nullness.compatqual.NullableDecl; import java.io.File; import java.io.FileInputStream; @@ -13,6 +18,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; @@ -39,8 +45,11 @@ import eu.siacs.conversations.xml.Namespace; import eu.siacs.conversations.xmpp.OnIqPacketReceived; import eu.siacs.conversations.xmpp.jingle.stanzas.Content; import eu.siacs.conversations.xmpp.jingle.stanzas.FileTransferDescription; +import eu.siacs.conversations.xmpp.jingle.stanzas.GenericTransportInfo; +import eu.siacs.conversations.xmpp.jingle.stanzas.IbbTransportInfo; import eu.siacs.conversations.xmpp.jingle.stanzas.JinglePacket; import eu.siacs.conversations.xmpp.jingle.stanzas.Reason; +import eu.siacs.conversations.xmpp.jingle.stanzas.S5BTransportInfo; import eu.siacs.conversations.xmpp.stanzas.IqPacket; import rocks.xmpp.addr.Jid; @@ -54,7 +63,9 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple private static final int JINGLE_STATUS_FAILED = 99; private static final int JINGLE_STATUS_OFFERED = -1; - private int ibbBlockSize = 8192; + private static final int MAX_IBB_BLOCK_SIZE = 8192; + + private int ibbBlockSize = MAX_IBB_BLOCK_SIZE; private int mJingleStatus = JINGLE_STATUS_OFFERED; //migrate to enum private int mStatus = Transferable.STATUS_UNKNOWN; @@ -72,7 +83,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple private String contentName; private Content.Creator contentCreator; - private Transport initialTransport; + private Class initialTransport; private boolean remoteSupportsOmemoJet; private int mProgress = 0; @@ -276,8 +287,10 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple } else if (action == JinglePacket.Action.TRANSPORT_INFO) { receiveTransportInfo(packet); } else if (action == JinglePacket.Action.TRANSPORT_REPLACE) { - if (packet.getJingleContent().hasIbbTransport()) { - receiveFallbackToIbb(packet); + final Content content = packet.getJingleContent(); + final GenericTransportInfo transportInfo = content == null ? null : content.getTransport(); + if (transportInfo instanceof IbbTransportInfo) { + receiveFallbackToIbb(packet, (IbbTransportInfo) transportInfo); } else { Log.d(Config.LOGTAG, "trying to fallback to something unknown" + packet.toString()); respondToIq(packet, false); @@ -333,7 +346,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple this.message = message; final List remoteFeatures = getRemoteFeatures(); final FileTransferDescription.Version remoteVersion = getAvailableFileTransferVersion(remoteFeatures); - this.initialTransport = remoteFeatures.contains(Namespace.JINGLE_TRANSPORTS_S5B) ? Transport.SOCKS : Transport.IBB; + this.initialTransport = remoteFeatures.contains(Namespace.JINGLE_TRANSPORTS_S5B) ? S5BTransportInfo.class : IbbTransportInfo.class; this.remoteSupportsOmemoJet = remoteFeatures.contains(Namespace.JINGLE_ENCRYPTED_TRANSPORT_OMEMO); this.message.setTransferable(this); this.mStatus = Transferable.STATUS_UPLOADING; @@ -341,7 +354,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple this.responder = this.id.counterPart; this.transportId = JingleConnectionManager.nextRandomId(); this.setupDescription(remoteVersion); - if (this.initialTransport == Transport.IBB) { + if (this.initialTransport == IbbTransportInfo.class) { this.sendInitRequest(); } else { gatherAndConnectDirectCandidates(); @@ -425,31 +438,31 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple this.initiator = this.id.counterPart; this.responder = this.id.account.getJid(); final Content content = packet.getJingleContent(); + final GenericTransportInfo transportInfo = content.getTransport(); this.contentCreator = content.getCreator(); - this.initialTransport = content.hasSocks5Transport() ? Transport.SOCKS : Transport.IBB; this.contentName = content.getAttribute("name"); - this.transportId = content.getTransportId(); - - if (this.initialTransport == Transport.SOCKS) { - this.mergeCandidates(JingleCandidate.parse(content.socks5transport().getChildren())); - } else if (this.initialTransport == Transport.IBB) { - final String receivedBlockSize = content.ibbTransport().getAttribute("block-size"); - if (receivedBlockSize != null) { - try { - this.ibbBlockSize = Math.min(Integer.parseInt(receivedBlockSize), this.ibbBlockSize); - } catch (NumberFormatException e) { - Log.d(Config.LOGTAG, "number format exception " + e.getMessage()); - respondToIq(packet, false); - this.fail(); - return; - } - } else { - Log.d(Config.LOGTAG, "received block size was null"); + if (transportInfo instanceof S5BTransportInfo) { + final S5BTransportInfo s5BTransportInfo = (S5BTransportInfo) transportInfo; + this.transportId = s5BTransportInfo.getTransportId(); + this.initialTransport = s5BTransportInfo.getClass(); + this.mergeCandidates(s5BTransportInfo.getCandidates()); + } else if (transportInfo instanceof IbbTransportInfo) { + final IbbTransportInfo ibbTransportInfo = (IbbTransportInfo) transportInfo; + this.initialTransport = ibbTransportInfo.getClass(); + this.transportId = ibbTransportInfo.getTransportId(); + final int remoteBlockSize = ibbTransportInfo.getBlockSize(); + if (remoteBlockSize <= 0) { + Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": remote party requested invalid ibb block size"); respondToIq(packet, false); this.fail(); - return; } + this.ibbBlockSize = Math.min(MAX_IBB_BLOCK_SIZE, ibbTransportInfo.getBlockSize()); + } else { + Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": remote tried to use unknown transport " + transportInfo.getNamespace()); + respondToIq(packet, false); + this.fail(); + return; } this.description = (FileTransferDescription) content.getDescription(); @@ -562,7 +575,6 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple private void sendInitRequest() { final JinglePacket packet = this.bootstrapPacket(JinglePacket.Action.SESSION_INITIATE); final Content content = new Content(this.contentCreator, this.contentName); - content.setTransportId(this.transportId); if (message.getEncryption() == Message.ENCRYPTION_AXOLOTL && remoteSupportsOmemoJet) { Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": remote announced support for JET"); final Element security = new Element("security", Namespace.JINGLE_ENCRYPTED_TRANSPORT); @@ -580,14 +592,13 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple fail(e.getMessage()); return; } - content.setTransportId(this.transportId); - if (this.initialTransport == Transport.IBB) { - content.ibbTransport().setAttribute("block-size", Integer.toString(this.ibbBlockSize)); + if (this.initialTransport == IbbTransportInfo.class) { + content.setTransport(new IbbTransportInfo(this.transportId, this.ibbBlockSize)); Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": sending IBB offer"); } else { - final List candidates = getCandidatesAsElements(); + final Collection candidates = getOurCandidates(); + content.setTransport(new S5BTransportInfo(this.transportId, candidates)); Log.d(Config.LOGTAG, String.format("%s: sending S5B offer with %d candidates", id.account.getJid().asBareJid(), candidates.size())); - content.socks5transport().setChildren(candidates); } packet.setJingleContent(content); this.sendJinglePacket(packet, (account, response) -> { @@ -618,21 +629,15 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple this.sendJinglePacket(packet); } - private List getCandidatesAsElements() { - List elements = new ArrayList<>(); - for (JingleCandidate c : this.candidates) { - if (c.isOurs()) { - elements.add(c.toElement()); - } - } - return elements; + public Collection getOurCandidates() { + return Collections2.filter(this.candidates, c -> c != null && c.isOurs()); } private void sendAccept() { mJingleStatus = JINGLE_STATUS_ACCEPTED; this.mStatus = Transferable.STATUS_DOWNLOADING; this.jingleConnectionManager.updateConversationUi(true); - if (initialTransport == Transport.SOCKS) { + if (initialTransport == S5BTransportInfo.class) { sendAcceptSocks(); } else { sendAcceptIbb(); @@ -645,7 +650,6 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple final JinglePacket packet = bootstrapPacket(JinglePacket.Action.SESSION_ACCEPT); final Content content = new Content(contentCreator, contentName); content.setDescription(this.description); - content.setTransportId(transportId); if (success && candidate != null && !equalCandidateExists(candidate)) { final JingleSocks5Transport socksConnection = new JingleSocks5Transport(this, candidate); connections.put(candidate.getCid(), socksConnection); @@ -654,7 +658,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple @Override public void failed() { Log.d(Config.LOGTAG, "connection to our own proxy65 candidate failed"); - content.socks5transport().setChildren(getCandidatesAsElements()); + content.setTransport(new S5BTransportInfo(transportId, getOurCandidates())); packet.setJingleContent(content); sendJinglePacket(packet); connectNextCandidate(); @@ -664,7 +668,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple public void established() { Log.d(Config.LOGTAG, "connected to proxy65 candidate"); mergeCandidate(candidate); - content.socks5transport().setChildren(getCandidatesAsElements()); + content.setTransport(new S5BTransportInfo(transportId, getOurCandidates())); packet.setJingleContent(content); sendJinglePacket(packet); connectNextCandidate(); @@ -672,7 +676,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple }); } else { Log.d(Config.LOGTAG, "did not find a proxy65 candidate for ourselves"); - content.socks5transport().setChildren(getCandidatesAsElements()); + content.setTransport(new S5BTransportInfo(transportId, getOurCandidates())); packet.setJingleContent(content); sendJinglePacket(packet); connectNextCandidate(); @@ -685,8 +689,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple final JinglePacket packet = bootstrapPacket(JinglePacket.Action.SESSION_ACCEPT); final Content content = new Content(contentCreator, contentName); content.setDescription(this.description); - content.setTransportId(transportId); - content.ibbTransport().setAttribute("block-size", this.ibbBlockSize); + content.setTransport(new IbbTransportInfo(this.transportId, this.ibbBlockSize)); packet.setJingleContent(content); this.transport.receive(file, onFileTransmissionStatusChanged); this.sendJinglePacket(packet); @@ -719,22 +722,21 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple } this.mJingleStatus = JINGLE_STATUS_ACCEPTED; xmppConnectionService.markMessage(message, Message.STATUS_UNSEND); - Content content = packet.getJingleContent(); - if (content.hasSocks5Transport()) { + final Content content = packet.getJingleContent(); + final GenericTransportInfo transportInfo = content.getTransport(); + //TODO we want to fail if transportInfo doesn’t match our intialTransport and/or our id + if (transportInfo instanceof S5BTransportInfo) { + final S5BTransportInfo s5BTransportInfo = (S5BTransportInfo) transportInfo; respondToIq(packet, true); - mergeCandidates(JingleCandidate.parse(content.socks5transport().getChildren())); + //TODO calling merge is probably a bug because that might eliminate candidates of the other party and lead to us not sending accept/deny + //TODO: we probably just want to call add + mergeCandidates(s5BTransportInfo.getCandidates()); this.connectNextCandidate(); - } else if (content.hasIbbTransport()) { - String receivedBlockSize = packet.getJingleContent().ibbTransport().getAttribute("block-size"); - if (receivedBlockSize != null) { - try { - int bs = Integer.parseInt(receivedBlockSize); - if (bs > this.ibbBlockSize) { - this.ibbBlockSize = bs; - } - } catch (Exception e) { - Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": unable to parse block size in session-accept"); - } + } else if (transportInfo instanceof IbbTransportInfo) { + final IbbTransportInfo ibbTransportInfo = (IbbTransportInfo) transportInfo; + final int remoteBlockSize = ibbTransportInfo.getBlockSize(); + if (remoteBlockSize > 0) { + this.ibbBlockSize = Math.min(ibbBlockSize, remoteBlockSize); } respondToIq(packet, true); this.transport = new JingleInBandTransport(this, this.transportId, this.ibbBlockSize); @@ -746,13 +748,15 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple private void receiveTransportInfo(JinglePacket packet) { final Content content = packet.getJingleContent(); - if (content.hasSocks5Transport()) { - if (content.socks5transport().hasChild("activated")) { + final GenericTransportInfo transportInfo = content.getTransport(); + if (transportInfo instanceof S5BTransportInfo) { + final S5BTransportInfo s5BTransportInfo = (S5BTransportInfo) transportInfo; + if (s5BTransportInfo.hasChild("activated")) { respondToIq(packet, true); if ((this.transport != null) && (this.transport instanceof JingleSocks5Transport)) { onProxyActivated.success(); } else { - String cid = content.socks5transport().findChild("activated").getAttribute("cid"); + String cid = s5BTransportInfo.findChild("activated").getAttribute("cid"); Log.d(Config.LOGTAG, "received proxy activated (" + cid + ")prior to choosing our own transport"); JingleSocks5Transport connection = this.connections.get(cid); @@ -764,18 +768,18 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple this.fail(); } } - } else if (content.socks5transport().hasChild("proxy-error")) { + } else if (s5BTransportInfo.hasChild("proxy-error")) { respondToIq(packet, true); onProxyActivated.failed(); - } else if (content.socks5transport().hasChild("candidate-error")) { + } else if (s5BTransportInfo.hasChild("candidate-error")) { Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": received candidate error"); respondToIq(packet, true); this.receivedCandidate = true; if (mJingleStatus == JINGLE_STATUS_ACCEPTED && this.sentCandidate) { this.connect(); } - } else if (content.socks5transport().hasChild("candidate-used")) { - String cid = content.socks5transport().findChild("candidate-used").getAttribute("cid"); + } else if (s5BTransportInfo.hasChild("candidate-used")) { + String cid = s5BTransportInfo.findChild("candidate-used").getAttribute("cid"); if (cid != null) { Log.d(Config.LOGTAG, "candidate used by counterpart:" + cid); JingleCandidate candidate = getCandidate(cid); @@ -912,15 +916,13 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple JinglePacket packet = this.bootstrapPacket(JinglePacket.Action.TRANSPORT_REPLACE); Content content = new Content(this.contentCreator, this.contentName); this.transportId = JingleConnectionManager.nextRandomId(); - content.setTransportId(this.transportId); - content.ibbTransport().setAttribute("block-size", - Integer.toString(this.ibbBlockSize)); + content.setTransport(new IbbTransportInfo(this.transportId, this.ibbBlockSize)); packet.setJingleContent(content); this.sendJinglePacket(packet); } - private void receiveFallbackToIbb(JinglePacket packet) { + private void receiveFallbackToIbb(final JinglePacket packet, final IbbTransportInfo transportInfo) { if (initiating()) { Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": received out of order transport-replace (we were initiating)"); respondToIqWithOutOfOrder(packet); @@ -934,25 +936,19 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple } this.proxyActivationFailed = false; //fallback received; now we no longer need to accept another one; Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": receiving fallback to ibb"); - final String receivedBlockSize = packet.getJingleContent().ibbTransport().getAttribute("block-size"); - if (receivedBlockSize != null) { - try { - final int bs = Integer.parseInt(receivedBlockSize); - if (bs < this.ibbBlockSize) { - this.ibbBlockSize = bs; - } - } catch (NumberFormatException e) { - Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": unable to parse block size in transport-replace"); - } + final int remoteBlockSize = transportInfo.getBlockSize(); + if (remoteBlockSize > 0) { + this.ibbBlockSize = Math.min(MAX_IBB_BLOCK_SIZE, remoteBlockSize); + } else { + Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": unable to parse block size in transport-replace"); } - this.transportId = packet.getJingleContent().getTransportId(); + this.transportId = transportInfo.getTransportId(); //TODO: handle the case where this is null by the remote party this.transport = new JingleInBandTransport(this, this.transportId, this.ibbBlockSize); final JinglePacket answer = bootstrapPacket(JinglePacket.Action.TRANSPORT_ACCEPT); final Content content = new Content(contentCreator, contentName); - content.ibbTransport().setAttribute("block-size", this.ibbBlockSize); - content.ibbTransport().setAttribute("sid", this.transportId); + content.setTransport(new IbbTransportInfo(this.transportId, this.ibbBlockSize)); answer.setJingleContent(content); respondToIq(packet, true); @@ -983,20 +979,15 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple return; } this.proxyActivationFailed = false; //fallback accepted; now we no longer need to accept another one; - if (packet.getJingleContent().hasIbbTransport()) { - final Element ibbTransport = packet.getJingleContent().ibbTransport(); - final String receivedBlockSize = ibbTransport.getAttribute("block-size"); - final String sid = ibbTransport.getAttribute("sid"); - if (receivedBlockSize != null) { - try { - int bs = Integer.parseInt(receivedBlockSize); - if (bs < this.ibbBlockSize) { - this.ibbBlockSize = bs; - } - } catch (NumberFormatException e) { - Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": unable to parse block size in transport-accept"); - } + final Content content = packet.getJingleContent(); + final GenericTransportInfo transportInfo = content == null ? null : content.getTransport(); + if (transportInfo instanceof IbbTransportInfo) { + final IbbTransportInfo ibbTransportInfo = (IbbTransportInfo) transportInfo; + final int remoteBlockSize = ibbTransportInfo.getBlockSize(); + if (remoteBlockSize > 0) { + this.ibbBlockSize = Math.min(MAX_IBB_BLOCK_SIZE, remoteBlockSize); } + final String sid = ibbTransportInfo.getTransportId(); this.transport = new JingleInBandTransport(this, this.transportId, this.ibbBlockSize); if (sid == null || !sid.equals(this.transportId)) { @@ -1138,8 +1129,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple private void sendProxyActivated(String cid) { final JinglePacket packet = bootstrapPacket(JinglePacket.Action.TRANSPORT_INFO); final Content content = new Content(this.contentCreator, this.contentName); - content.setTransportId(this.transportId); - content.socks5transport().addChild("activated").setAttribute("cid", cid); + content.setTransport(new S5BTransportInfo(this.transportId, new Element("activated").setAttribute("cid", cid))); packet.setJingleContent(content); this.sendJinglePacket(packet); } @@ -1147,17 +1137,15 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple private void sendProxyError() { final JinglePacket packet = bootstrapPacket(JinglePacket.Action.TRANSPORT_INFO); final Content content = new Content(this.contentCreator, this.contentName); - content.setTransportId(this.transportId); - content.socks5transport().addChild("proxy-error"); + content.setTransport(new S5BTransportInfo(this.transportId, new Element("proxy-error"))); packet.setJingleContent(content); this.sendJinglePacket(packet); } private void sendCandidateUsed(final String cid) { JinglePacket packet = bootstrapPacket(JinglePacket.Action.TRANSPORT_INFO); - Content content = new Content(this.contentCreator, this.contentName); - content.setTransportId(this.transportId); - content.socks5transport().addChild("candidate-used").setAttribute("cid", cid); + final Content content = new Content(this.contentCreator, this.contentName); + content.setTransport(new S5BTransportInfo(this.transportId, new Element("candidate-used").setAttribute("cid", cid))); packet.setJingleContent(content); this.sentCandidate = true; if ((receivedCandidate) && (mJingleStatus == JINGLE_STATUS_ACCEPTED)) { @@ -1170,8 +1158,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": sending candidate error"); JinglePacket packet = bootstrapPacket(JinglePacket.Action.TRANSPORT_INFO); Content content = new Content(this.contentCreator, this.contentName); - content.setTransportId(this.transportId); - content.socks5transport().addChild("candidate-error"); + content.setTransport(new S5BTransportInfo(this.transportId, new Element("candidate-error"))); packet.setJingleContent(content); this.sentCandidate = true; this.sendJinglePacket(packet); diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/Transport.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/Transport.java deleted file mode 100644 index 4d0fb4b65..000000000 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/Transport.java +++ /dev/null @@ -1,5 +0,0 @@ -package eu.siacs.conversations.xmpp.jingle; - -public enum Transport { - SOCKS, IBB -} diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/Content.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/Content.java index 34c0c706f..ad16041a3 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/Content.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/Content.java @@ -11,11 +11,6 @@ import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xml.Namespace; public class Content extends Element { - private String transportId; - - - //refactor to getDescription and getTransport - //return either FileTransferDescription or GenericDescription or RtpDescription (all extend Description interface) public Content(final Creator creator, final String name) { super("content", Namespace.JINGLE); @@ -70,43 +65,24 @@ public class Content extends Element { return description == null ? null : description.getNamespace(); } - public String getTransportId() { - if (hasSocks5Transport()) { - this.transportId = socks5transport().getAttribute("sid"); - } else if (hasIbbTransport()) { - this.transportId = ibbTransport().getAttribute("sid"); + public GenericTransportInfo getTransport() { + final Element transport = this.findChild("transport"); + final String namespace = transport == null ? null : transport.getNamespace(); + if (Namespace.JINGLE_TRANSPORTS_IBB.equals(namespace)) { + return IbbTransportInfo.upgrade(transport); + } else if (Namespace.JINGLE_TRANSPORTS_S5B.equals(namespace)) { + return S5BTransportInfo.upgrade(transport); + } else if (Namespace.JINGLE_TRANSPORT_ICE_UDP.equals(namespace)) { + return IceUdpTransportInfo.upgrade(transport); + } else if (transport != null) { + return GenericTransportInfo.upgrade(transport); + } else { + return null; } - return this.transportId; } - public void setTransportId(String sid) { - this.transportId = sid; - } - - public Element socks5transport() { - Element transport = this.findChild("transport", Namespace.JINGLE_TRANSPORTS_S5B); - if (transport == null) { - transport = this.addChild("transport", Namespace.JINGLE_TRANSPORTS_S5B); - transport.setAttribute("sid", this.transportId); - } - return transport; - } - - public Element ibbTransport() { - Element transport = this.findChild("transport", Namespace.JINGLE_TRANSPORTS_IBB); - if (transport == null) { - transport = this.addChild("transport", Namespace.JINGLE_TRANSPORTS_IBB); - transport.setAttribute("sid", this.transportId); - } - return transport; - } - - public boolean hasSocks5Transport() { - return this.hasChild("transport", Namespace.JINGLE_TRANSPORTS_S5B); - } - - public boolean hasIbbTransport() { - return this.hasChild("transport", Namespace.JINGLE_TRANSPORTS_IBB); + public void setTransport(GenericTransportInfo transportInfo) { + this.addChild(transportInfo); } public enum Creator { diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/GenericDescription.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/GenericDescription.java index 0e3c5a7f1..a8db0d09f 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/GenericDescription.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/GenericDescription.java @@ -6,7 +6,7 @@ import eu.siacs.conversations.xml.Element; public class GenericDescription extends Element { - protected GenericDescription(String name, final String namespace) { + GenericDescription(String name, final String namespace) { super(name, namespace); } diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/GenericTransportInfo.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/GenericTransportInfo.java new file mode 100644 index 000000000..4c5c77388 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/GenericTransportInfo.java @@ -0,0 +1,20 @@ +package eu.siacs.conversations.xmpp.jingle.stanzas; + +import com.google.common.base.Preconditions; + +import eu.siacs.conversations.xml.Element; + +public class GenericTransportInfo extends Element { + + protected GenericTransportInfo(String name, String xmlns) { + super(name, xmlns); + } + + public static GenericTransportInfo upgrade(final Element element) { + Preconditions.checkArgument("transport".equals(element.getName())); + final GenericTransportInfo transport = new GenericTransportInfo("transport", element.getNamespace()); + transport.setAttributes(element.getAttributes()); + transport.setChildren(element.getChildren()); + return transport; + } +} diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/IbbTransportInfo.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/IbbTransportInfo.java new file mode 100644 index 000000000..90fb32903 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/IbbTransportInfo.java @@ -0,0 +1,46 @@ +package eu.siacs.conversations.xmpp.jingle.stanzas; + +import com.google.common.base.Preconditions; + +import eu.siacs.conversations.xml.Element; +import eu.siacs.conversations.xml.Namespace; + +public class IbbTransportInfo extends GenericTransportInfo { + + private IbbTransportInfo(final String name, final String xmlns) { + super(name, xmlns); + } + + public IbbTransportInfo(final String transportId, final int blockSize) { + super("transport", Namespace.JINGLE_TRANSPORTS_IBB); + Preconditions.checkNotNull(transportId, "Transport ID can not be null"); + Preconditions.checkArgument(blockSize > 0, "Block size must be larger than 0"); + this.setAttribute("block-size", blockSize); + this.setAttribute("sid", transportId); + } + + public String getTransportId() { + return this.getAttribute("sid"); + } + + public int getBlockSize() { + final String blockSize = this.getAttribute("block-size"); + if (blockSize == null) { + return 0; + } + try { + return Integer.parseInt(blockSize); + } catch (NumberFormatException e) { + return 0; + } + } + + public static IbbTransportInfo upgrade(final Element element) { + Preconditions.checkArgument("transport".equals(element.getName()), "Name of provided element is not transport"); + Preconditions.checkArgument(Namespace.JINGLE_TRANSPORTS_IBB.equals(element.getNamespace()), "Element does not match ibb transport namespace"); + final IbbTransportInfo transportInfo = new IbbTransportInfo("transport", Namespace.JINGLE_TRANSPORTS_IBB); + transportInfo.setAttributes(element.getAttributes()); + transportInfo.setChildren(element.getChildren()); + return transportInfo; + } +} diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/IceUdpTransportInfo.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/IceUdpTransportInfo.java new file mode 100644 index 000000000..00beac65c --- /dev/null +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/IceUdpTransportInfo.java @@ -0,0 +1,22 @@ +package eu.siacs.conversations.xmpp.jingle.stanzas; + +import com.google.common.base.Preconditions; + +import eu.siacs.conversations.xml.Element; +import eu.siacs.conversations.xml.Namespace; + +public class IceUdpTransportInfo extends GenericTransportInfo { + + private IceUdpTransportInfo(final String name, final String xmlns) { + super(name, xmlns); + } + + public static IceUdpTransportInfo upgrade(final Element element) { + Preconditions.checkArgument("transport".equals(element.getName()), "Name of provided element is not transport"); + Preconditions.checkArgument(Namespace.JINGLE_TRANSPORT_ICE_UDP.equals(element.getNamespace()), "Element does not match ice-udp transport namespace"); + final IceUdpTransportInfo transportInfo = new IceUdpTransportInfo("transport", Namespace.JINGLE_TRANSPORT_ICE_UDP); + transportInfo.setAttributes(element.getAttributes()); + transportInfo.setChildren(element.getChildren()); + return transportInfo; + } +} diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/S5BTransportInfo.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/S5BTransportInfo.java new file mode 100644 index 000000000..8f8f13416 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/S5BTransportInfo.java @@ -0,0 +1,50 @@ +package eu.siacs.conversations.xmpp.jingle.stanzas; + +import com.google.common.base.Preconditions; + +import java.util.Collection; +import java.util.List; + +import eu.siacs.conversations.xml.Element; +import eu.siacs.conversations.xml.Namespace; +import eu.siacs.conversations.xmpp.jingle.JingleCandidate; + +public class S5BTransportInfo extends GenericTransportInfo { + + private S5BTransportInfo(final String name, final String xmlns) { + super(name, xmlns); + } + + public String getTransportId() { + return this.getAttribute("sid"); + } + + public S5BTransportInfo(final String transportId, final Collection candidates) { + super("transport", Namespace.JINGLE_TRANSPORTS_S5B); + Preconditions.checkNotNull(transportId,"transport id must not be null"); + for(JingleCandidate candidate : candidates) { + this.addChild(candidate.toElement()); + } + this.setAttribute("sid", transportId); + } + + public S5BTransportInfo(final String transportId, final Element child) { + super("transport", Namespace.JINGLE_TRANSPORTS_S5B); + Preconditions.checkNotNull(transportId,"transport id must not be null"); + this.addChild(child); + this.setAttribute("sid", transportId); + } + + public List getCandidates() { + return JingleCandidate.parse(this.getChildren()); + } + + public static S5BTransportInfo upgrade(final Element element) { + Preconditions.checkArgument("transport".equals(element.getName()), "Name of provided element is not transport"); + Preconditions.checkArgument(Namespace.JINGLE_TRANSPORTS_S5B.equals(element.getNamespace()), "Element does not match s5b transport namespace"); + final S5BTransportInfo transportInfo = new S5BTransportInfo("transport", Namespace.JINGLE_TRANSPORTS_S5B); + transportInfo.setAttributes(element.getAttributes()); + transportInfo.setChildren(element.getChildren()); + return transportInfo; + } +}