diff options
| author | Alex Clayton <alex.clayton@isode.com> | 2016-03-16 15:45:11 (GMT) |
|---|---|---|
| committer | Alex Clayton <alex.clayton@isode.com> | 2016-03-16 15:57:40 (GMT) |
| commit | f693c8e0fa9c6a051cdf6260f131db3d9355b49f (patch) | |
| tree | 10ca50f0c3494566e005f9c202f7d3b6c6d036f9 | |
| parent | 8b9891afc85d114ff1e9c9a0291a4aaee8baeb09 (diff) | |
| download | stroke-f693c8e0fa9c6a051cdf6260f131db3d9355b49f.zip stroke-f693c8e0fa9c6a051cdf6260f131db3d9355b49f.tar.bz2 | |
Support early IBB use in Jingle File Transfer
As per swiften patch of the same name
(75703db2de5bbfb6622286600362016edb42dfb0).
Previously Jingle File Transfer in Stroke only used IBB transport as
fallback mechanism. With this patch Stroke will use IBB transport
candidates directly in the first session-initate/session-accept
message if the other party only supports IBB.
Test-information: Unit tests all pass.
Change-Id: Ice73a6028f10c63490bdb775a0a407fad48f587a
6 files changed, 78 insertions, 27 deletions
diff --git a/src/com/isode/stroke/filetransfer/DummyFileTransferTransporterFactory.java b/src/com/isode/stroke/filetransfer/DummyFileTransferTransporterFactory.java index 10b630d..1904944 100644 --- a/src/com/isode/stroke/filetransfer/DummyFileTransferTransporterFactory.java +++ b/src/com/isode/stroke/filetransfer/DummyFileTransferTransporterFactory.java | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2015 Isode Limited. | 2 | * Copyright (c) 2015-2016 Isode Limited. |
| 3 | * All rights reserved. | 3 | * All rights reserved. |
| 4 | * See the COPYING file for more information. | 4 | * See the COPYING file for more information. |
| 5 | */ | 5 | */ |
| @@ -51,13 +51,14 @@ class DummyFileTransferTransporter extends FileTransferTransporter { | |||
| 51 | TimerFactory timer, | 51 | TimerFactory timer, |
| 52 | CryptoProvider cryptoProvider, | 52 | CryptoProvider cryptoProvider, |
| 53 | IQRouter iqRouter, | 53 | IQRouter iqRouter, |
| 54 | final FileTransferOptions option) { | 54 | final FileTransferOptions ftOptions) { |
| 55 | initiator_ = initiator; | 55 | initiator_ = initiator; |
| 56 | responder_ = responder; | 56 | responder_ = responder; |
| 57 | role_ = role; | 57 | role_ = role; |
| 58 | s5bRegistry_ = s5bRegistry; | 58 | s5bRegistry_ = s5bRegistry; |
| 59 | crypto_ = cryptoProvider; | 59 | crypto_ = cryptoProvider; |
| 60 | iqRouter_ = iqRouter; | 60 | iqRouter_ = iqRouter; |
| 61 | ftOptions_ = new FileTransferOptions(ftOptions); | ||
| 61 | } | 62 | } |
| 62 | 63 | ||
| 63 | public void initialize() { | 64 | public void initialize() { |
| @@ -66,6 +67,12 @@ class DummyFileTransferTransporter extends FileTransferTransporter { | |||
| 66 | 67 | ||
| 67 | public void startGeneratingLocalCandidates() { | 68 | public void startGeneratingLocalCandidates() { |
| 68 | Vector<JingleS5BTransportPayload.Candidate> candidates = new Vector<JingleS5BTransportPayload.Candidate>(); | 69 | Vector<JingleS5BTransportPayload.Candidate> candidates = new Vector<JingleS5BTransportPayload.Candidate>(); |
| 70 | if (ftOptions_.isDirectAllowed()) { | ||
| 71 | JingleS5BTransportPayload.Candidate candidate = new JingleS5BTransportPayload.Candidate(); | ||
| 72 | candidate.cid = "123"; | ||
| 73 | candidate.priority = 1235; | ||
| 74 | candidates.add(candidate); | ||
| 75 | } | ||
| 69 | onLocalCandidatesGenerated.emit(s5bSessionID_, candidates, getSOCKS5DstAddr()); | 76 | onLocalCandidatesGenerated.emit(s5bSessionID_, candidates, getSOCKS5DstAddr()); |
| 70 | } | 77 | } |
| 71 | 78 | ||
| @@ -147,6 +154,7 @@ class DummyFileTransferTransporter extends FileTransferTransporter { | |||
| 147 | private CryptoProvider crypto_; | 154 | private CryptoProvider crypto_; |
| 148 | private String s5bSessionID_; | 155 | private String s5bSessionID_; |
| 149 | private IQRouter iqRouter_; | 156 | private IQRouter iqRouter_; |
| 157 | private final FileTransferOptions ftOptions_; | ||
| 150 | }; | 158 | }; |
| 151 | 159 | ||
| 152 | public class DummyFileTransferTransporterFactory implements FileTransferTransporterFactory { | 160 | public class DummyFileTransferTransporterFactory implements FileTransferTransporterFactory { |
diff --git a/src/com/isode/stroke/filetransfer/IncomingFileTransferManager.java b/src/com/isode/stroke/filetransfer/IncomingFileTransferManager.java index 7166d67..06ed3ab 100644 --- a/src/com/isode/stroke/filetransfer/IncomingFileTransferManager.java +++ b/src/com/isode/stroke/filetransfer/IncomingFileTransferManager.java | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2010-2015 Isode Limited. | 2 | * Copyright (c) 2010-2016 Isode Limited. |
| 3 | * All rights reserved. | 3 | * All rights reserved. |
| 4 | * See the COPYING file for more information. | 4 | * See the COPYING file for more information. |
| 5 | */ | 5 | */ |
| @@ -15,6 +15,7 @@ import com.isode.stroke.signals.Signal1; | |||
| 15 | import com.isode.stroke.jingle.IncomingJingleSessionHandler; | 15 | import com.isode.stroke.jingle.IncomingJingleSessionHandler; |
| 16 | import com.isode.stroke.jingle.JingleSessionManager; | 16 | import com.isode.stroke.jingle.JingleSessionManager; |
| 17 | import com.isode.stroke.jingle.JingleSession; | 17 | import com.isode.stroke.jingle.JingleSession; |
| 18 | import com.isode.stroke.elements.JingleIBBTransportPayload; | ||
| 18 | import com.isode.stroke.elements.JinglePayload; | 19 | import com.isode.stroke.elements.JinglePayload; |
| 19 | import com.isode.stroke.elements.JingleContentPayload; | 20 | import com.isode.stroke.elements.JingleContentPayload; |
| 20 | import com.isode.stroke.elements.JingleFileTransferDescription; | 21 | import com.isode.stroke.elements.JingleFileTransferDescription; |
| @@ -24,6 +25,7 @@ import com.isode.stroke.network.TimerFactory; | |||
| 24 | import com.isode.stroke.crypto.CryptoProvider; | 25 | import com.isode.stroke.crypto.CryptoProvider; |
| 25 | import com.isode.stroke.queries.IQRouter; | 26 | import com.isode.stroke.queries.IQRouter; |
| 26 | import com.isode.stroke.jid.JID; | 27 | import com.isode.stroke.jid.JID; |
| 28 | |||
| 27 | import java.util.logging.Logger; | 29 | import java.util.logging.Logger; |
| 28 | import java.util.Vector; | 30 | import java.util.Vector; |
| 29 | 31 | ||
| @@ -55,7 +57,8 @@ public class IncomingFileTransferManager implements IncomingJingleSessionHandler | |||
| 55 | final JID recipient) { | 57 | final JID recipient) { |
| 56 | if (Jingle.getContentWithDescription(contents, new JingleFileTransferDescription()) != null) { | 58 | if (Jingle.getContentWithDescription(contents, new JingleFileTransferDescription()) != null) { |
| 57 | JingleContentPayload content = Jingle.getContentWithDescription(contents, new JingleFileTransferDescription()); | 59 | JingleContentPayload content = Jingle.getContentWithDescription(contents, new JingleFileTransferDescription()); |
| 58 | if (content.getTransport(new JingleS5BTransportPayload()) != null) { | 60 | if ( (content.getTransport(new JingleS5BTransportPayload()) != null) |
| 61 | || (content.getTransport(new JingleIBBTransportPayload()) != null) ) { | ||
| 59 | JingleFileTransferDescription description = content.getDescription(new JingleFileTransferDescription()); | 62 | JingleFileTransferDescription description = content.getDescription(new JingleFileTransferDescription()); |
| 60 | if (description != null) { | 63 | if (description != null) { |
| 61 | IncomingJingleFileTransfer transfer = new IncomingJingleFileTransfer( | 64 | IncomingJingleFileTransfer transfer = new IncomingJingleFileTransfer( |
diff --git a/src/com/isode/stroke/filetransfer/IncomingJingleFileTransfer.java b/src/com/isode/stroke/filetransfer/IncomingJingleFileTransfer.java index 1c67014..f6aa01f 100644 --- a/src/com/isode/stroke/filetransfer/IncomingJingleFileTransfer.java +++ b/src/com/isode/stroke/filetransfer/IncomingJingleFileTransfer.java | |||
| @@ -171,16 +171,16 @@ public class IncomingJingleFileTransfer extends JingleFileTransfer implements In | |||
| 171 | } | 171 | } |
| 172 | }); | 172 | }); |
| 173 | 173 | ||
| 174 | if (initialContent.getTransport(new JingleS5BTransportPayload()) != null) { | 174 | JingleS5BTransportPayload s5bTransport = initialContent.getTransport(new JingleS5BTransportPayload()); |
| 175 | JingleS5BTransportPayload s5bTransport = initialContent.getTransport(new JingleS5BTransportPayload()); | 175 | JingleIBBTransportPayload ibbTransport = initialContent.getTransport(new JingleIBBTransportPayload()); |
| 176 | if (s5bTransport != null) { | ||
| 176 | logger_.fine("Got S5B transport as initial payload.\n"); | 177 | logger_.fine("Got S5B transport as initial payload.\n"); |
| 177 | setTransporter(transporterFactory.createResponderTransporter(getInitiator(), getResponder(), s5bTransport.getSessionID(), options)); | 178 | setTransporter(transporterFactory.createResponderTransporter(getInitiator(), getResponder(), s5bTransport.getSessionID(), options)); |
| 178 | transporter.addRemoteCandidates(s5bTransport.getCandidates(), s5bTransport.getDstAddr()); | 179 | transporter.addRemoteCandidates(s5bTransport.getCandidates(), s5bTransport.getDstAddr()); |
| 179 | setInternalState(State.GeneratingInitialLocalCandidates); | 180 | setInternalState(State.GeneratingInitialLocalCandidates); |
| 180 | transporter.startGeneratingLocalCandidates(); | 181 | transporter.startGeneratingLocalCandidates(); |
| 181 | } | 182 | } |
| 182 | else if(initialContent.getTransport(new JingleIBBTransportPayload()) != null) { | 183 | else if(ibbTransport != null && options.isInBandAllowed()) { |
| 183 | JingleIBBTransportPayload ibbTransport = initialContent.getTransport(new JingleIBBTransportPayload()); | ||
| 184 | logger_.fine("Got IBB transport as initial payload.\n"); | 184 | logger_.fine("Got IBB transport as initial payload.\n"); |
| 185 | setTransporter(transporterFactory.createResponderTransporter(getInitiator(), getResponder(), ibbTransport.getSessionID(), options)); | 185 | setTransporter(transporterFactory.createResponderTransporter(getInitiator(), getResponder(), ibbTransport.getSessionID(), options)); |
| 186 | 186 | ||
| @@ -189,8 +189,9 @@ public class IncomingJingleFileTransfer extends JingleFileTransfer implements In | |||
| 189 | session.sendAccept(getContentID(), initialContent.getDescriptions().get(0), ibbTransport); | 189 | session.sendAccept(getContentID(), initialContent.getDescriptions().get(0), ibbTransport); |
| 190 | } | 190 | } |
| 191 | else { | 191 | else { |
| 192 | // Can't happen, because the transfer would have been rejected automatically | 192 | // This might happen on incoming transfer which only list transport methods we are not allowed to use due to file-transfer options. |
| 193 | assert(false); | 193 | session.sendTerminate(JinglePayload.Reason.Type.UnsupportedTransports); |
| 194 | setFinishedState(FileTransfer.State.Type.Failed, new FileTransferError(FileTransferError.Type.PeerError)); | ||
| 194 | } | 195 | } |
| 195 | } | 196 | } |
| 196 | 197 | ||
diff --git a/src/com/isode/stroke/filetransfer/OutgoingJingleFileTransfer.java b/src/com/isode/stroke/filetransfer/OutgoingJingleFileTransfer.java index aa38022..e2117b6 100644 --- a/src/com/isode/stroke/filetransfer/OutgoingJingleFileTransfer.java +++ b/src/com/isode/stroke/filetransfer/OutgoingJingleFileTransfer.java | |||
| @@ -179,10 +179,19 @@ public class OutgoingJingleFileTransfer extends JingleFileTransfer implements Ou | |||
| 179 | logger_.warning("Incorrect state\n"); | 179 | logger_.warning("Incorrect state\n"); |
| 180 | return; | 180 | return; |
| 181 | } | 181 | } |
| 182 | 182 | ||
| 183 | setTransporter(transporterFactory.createInitiatorTransporter(getInitiator(), getResponder(), options)); | 183 | if (!options.isInBandAllowed() && !options.isDirectAllowed() |
| 184 | setInternalState(State.GeneratingInitialLocalCandidates); | 184 | && !options.isAssistedAllowed() && !options.isProxiedAllowed()) { |
| 185 | transporter.startGeneratingLocalCandidates(); | 185 | // Started outgoing file transfer while not supporting transport methods. |
| 186 | setFinishedState(FileTransfer.State.Type.Failed, | ||
| 187 | new FileTransferError(FileTransferError.Type.UnknownError)); | ||
| 188 | } | ||
| 189 | else { | ||
| 190 | setTransporter(transporterFactory.createInitiatorTransporter(getInitiator(), getResponder(), options)); | ||
| 191 | setInternalState(State.GeneratingInitialLocalCandidates); | ||
| 192 | transporter.startGeneratingLocalCandidates(); | ||
| 193 | } | ||
| 194 | |||
| 186 | } | 195 | } |
| 187 | 196 | ||
| 188 | /** | 197 | /** |
| @@ -217,6 +226,13 @@ public class OutgoingJingleFileTransfer extends JingleFileTransfer implements Ou | |||
| 217 | setInternalState(State.TryingCandidates); | 226 | setInternalState(State.TryingCandidates); |
| 218 | transporter.startTryingRemoteCandidates(); | 227 | transporter.startTryingRemoteCandidates(); |
| 219 | } | 228 | } |
| 229 | else if (transportPayload instanceof JingleIBBTransportPayload) { | ||
| 230 | JingleIBBTransportPayload ibbPayload = (JingleIBBTransportPayload) transportPayload; | ||
| 231 | int blockSize = ibbPayload.getBlockSize() != null ? | ||
| 232 | ibbPayload.getBlockSize().intValue() : DEFAULT_BLOCK_SIZE; | ||
| 233 | startTransferring(transporter.createIBBSendSession(ibbPayload.getSessionID(), | ||
| 234 | blockSize, stream)); | ||
| 235 | } | ||
| 220 | else { | 236 | else { |
| 221 | logger_.fine("Unknown transport payload. Falling back.\n"); | 237 | logger_.fine("Unknown transport payload. Falling back.\n"); |
| 222 | fallback(); | 238 | fallback(); |
| @@ -310,14 +326,25 @@ public class OutgoingJingleFileTransfer extends JingleFileTransfer implements Ou | |||
| 310 | fileInfo.addHash(new HashElement("md5", new ByteArray())); | 326 | fileInfo.addHash(new HashElement("md5", new ByteArray())); |
| 311 | description.setFileInfo(fileInfo); | 327 | description.setFileInfo(fileInfo); |
| 312 | 328 | ||
| 313 | JingleS5BTransportPayload transport = new JingleS5BTransportPayload(); | 329 | JingleTransportPayload transport = null; |
| 314 | transport.setSessionID(s5bSessionID); | 330 | if (candidates.isEmpty()) { |
| 315 | transport.setMode(JingleS5BTransportPayload.Mode.TCPMode); | 331 | logger_.fine("no S5B candidate generated. Send IBB transport candidate.\n"); |
| 316 | transport.setDstAddr(dstAddr); | 332 | JingleIBBTransportPayload ibbTransport = new JingleIBBTransportPayload(); |
| 317 | for(JingleS5BTransportPayload.Candidate candidate : candidates) { | 333 | ibbTransport.setBlockSize(DEFAULT_BLOCK_SIZE); |
| 318 | transport.addCandidate(candidate); | 334 | ibbTransport.setSessionID(idGenerator.generateID()); |
| 319 | logger_.fine("\t" + "S5B candidate: " + candidate.hostPort.toString() + "\n"); | 335 | transport = ibbTransport; |
| 320 | } | 336 | } |
| 337 | else { | ||
| 338 | JingleS5BTransportPayload s5bTransport = new JingleS5BTransportPayload(); | ||
| 339 | s5bTransport.setSessionID(s5bSessionID); | ||
| 340 | s5bTransport.setMode(JingleS5BTransportPayload.Mode.TCPMode); | ||
| 341 | s5bTransport.setDstAddr(dstAddr); | ||
| 342 | for (JingleS5BTransportPayload.Candidate candidate : candidates) { | ||
| 343 | s5bTransport.addCandidate(candidate); | ||
| 344 | logger_.fine("\tS5B candidate: "+candidate.hostPort +"\n"); | ||
| 345 | } | ||
| 346 | transport = s5bTransport; | ||
| 347 | } | ||
| 321 | setInternalState(State.WaitingForAccept); | 348 | setInternalState(State.WaitingForAccept); |
| 322 | session.sendInitiate(contentID, description, transport); | 349 | session.sendInitiate(contentID, description, transport); |
| 323 | } | 350 | } |
diff --git a/src/com/isode/stroke/filetransfer/SOCKS5BytestreamServerManager.java b/src/com/isode/stroke/filetransfer/SOCKS5BytestreamServerManager.java index 590ee60..0d1f0a9 100644 --- a/src/com/isode/stroke/filetransfer/SOCKS5BytestreamServerManager.java +++ b/src/com/isode/stroke/filetransfer/SOCKS5BytestreamServerManager.java | |||
| @@ -126,6 +126,10 @@ public class SOCKS5BytestreamServerManager { | |||
| 126 | forwardPortRequest.stop(); | 126 | forwardPortRequest.stop(); |
| 127 | forwardPortRequest = null; | 127 | forwardPortRequest = null; |
| 128 | } | 128 | } |
| 129 | if (unforwardPortRequest != null) { | ||
| 130 | unforwardPortRequest.stop(); | ||
| 131 | unforwardPortRequest = null; | ||
| 132 | } | ||
| 129 | if (server != null) { | 133 | if (server != null) { |
| 130 | server.stop(); | 134 | server.stop(); |
| 131 | server = null; | 135 | server = null; |
diff --git a/test/com/isode/stroke/filetransfer/OutgoingJingleFileTransferTest.java b/test/com/isode/stroke/filetransfer/OutgoingJingleFileTransferTest.java index 4532efb..f8b76b8 100644 --- a/test/com/isode/stroke/filetransfer/OutgoingJingleFileTransferTest.java +++ b/test/com/isode/stroke/filetransfer/OutgoingJingleFileTransferTest.java | |||
| @@ -98,20 +98,25 @@ public class OutgoingJingleFileTransferTest { | |||
| 98 | assertNotNull(description); | 98 | assertNotNull(description); |
| 99 | assertEquals(1048576,description.getFileInfo().getSize()); | 99 | assertEquals(1048576,description.getFileInfo().getSize()); |
| 100 | 100 | ||
| 101 | JingleS5BTransportPayload transport = null; | 101 | JingleIBBTransportPayload transport = null; |
| 102 | if (call.payload instanceof JingleS5BTransportPayload) { | 102 | if (call.payload instanceof JingleIBBTransportPayload) { |
| 103 | transport = (JingleS5BTransportPayload) call.payload; | 103 | transport = (JingleIBBTransportPayload) call.payload; |
| 104 | } | ||
| 105 | else { | ||
| 106 | System.out.println(call.payload.getClass().getName()); | ||
| 104 | } | 107 | } |
| 105 | assertNotNull(transport); | 108 | assertNotNull(transport); |
| 106 | } | 109 | } |
| 107 | 110 | ||
| 108 | @Test | 111 | @Test |
| 109 | public void test_FallbackToIBBAfterFailingS5b() { | 112 | public void test_FallbackToIBBAfterFailingS5b() { |
| 110 | OutgoingJingleFileTransfer transfer = createTestling(); | 113 | OutgoingJingleFileTransfer transfer = |
| 114 | createTestling(new FileTransferOptions().withAssistedAllowed(true).withDirectAllowed(true).withProxiedAllowed(true)); | ||
| 111 | transfer.start(); | 115 | transfer.start(); |
| 112 | 116 | ||
| 113 | FakeJingleSession.InitiateCall call = getCall(FakeJingleSession.InitiateCall.class,0); | 117 | FakeJingleSession.InitiateCall call = getCall(FakeJingleSession.InitiateCall.class,0); |
| 114 | 118 | ||
| 119 | assertTrue(call.payload instanceof JingleS5BTransportPayload); | ||
| 115 | fakeJingleSession.handleSessionAcceptReceived(call.id, call.description, call.payload); | 120 | fakeJingleSession.handleSessionAcceptReceived(call.id, call.description, call.payload); |
| 116 | 121 | ||
| 117 | // Send candidate failure | 122 | // Send candidate failure |
| @@ -211,13 +216,16 @@ public class OutgoingJingleFileTransferTest { | |||
| 211 | } | 216 | } |
| 212 | 217 | ||
| 213 | private OutgoingJingleFileTransfer createTestling() { | 218 | private OutgoingJingleFileTransfer createTestling() { |
| 219 | return createTestling(new FileTransferOptions().withAssistedAllowed(false).withDirectAllowed(false).withProxiedAllowed(false)); | ||
| 220 | } | ||
| 221 | |||
| 222 | private OutgoingJingleFileTransfer createTestling(FileTransferOptions options) { | ||
| 214 | JID to = new JID("test@foo.com/bla"); | 223 | JID to = new JID("test@foo.com/bla"); |
| 215 | JingleFileTransferFileInfo fileInfo = new JingleFileTransferFileInfo(); | 224 | JingleFileTransferFileInfo fileInfo = new JingleFileTransferFileInfo(); |
| 216 | fileInfo.setDescription("some file"); | 225 | fileInfo.setDescription("some file"); |
| 217 | fileInfo.setName("test.bin"); | 226 | fileInfo.setName("test.bin"); |
| 218 | fileInfo.addHash(new HashElement("sha-1", new ByteArray())); | 227 | fileInfo.addHash(new HashElement("sha-1", new ByteArray())); |
| 219 | fileInfo.setSize(1024 * 1024); | 228 | fileInfo.setSize(1024 * 1024); |
| 220 | FileTransferOptions options = (new FileTransferOptions()).withAssistedAllowed(false).withDirectAllowed(false).withProxiedAllowed(false); | ||
| 221 | return new OutgoingJingleFileTransfer(to, fakeJingleSession, stream, | 229 | return new OutgoingJingleFileTransfer(to, fakeJingleSession, stream, |
| 222 | ftTransporterFactory, timeFactory, idGen, fileInfo, options, crypto); | 230 | ftTransporterFactory, timeFactory, idGen, fileInfo, options, crypto); |
| 223 | } | 231 | } |
Swift