mirror of
https://github.com/vanitasvitae/Smack.git
synced 2024-11-23 20:42:06 +01:00
Simplify content state handling, add Fallback test
This commit is contained in:
parent
9712dc1df7
commit
0d8b383b1c
3 changed files with 185 additions and 45 deletions
|
@ -67,41 +67,6 @@ public class JingleContent implements JingleTransportCallback, JingleSecurityCal
|
||||||
private final List<Callback> callbacks = Collections.synchronizedList(new ArrayList<Callback>());
|
private final List<Callback> callbacks = Collections.synchronizedList(new ArrayList<Callback>());
|
||||||
private final Set<String> transportBlacklist = Collections.synchronizedSet(new HashSet<String>());
|
private final Set<String> transportBlacklist = Collections.synchronizedSet(new HashSet<String>());
|
||||||
|
|
||||||
private short state;
|
|
||||||
|
|
||||||
public enum STATE {
|
|
||||||
pending_accept((short) 1),
|
|
||||||
pending_transmission_start((short) 2),
|
|
||||||
pending_transport_replace((short) 4),
|
|
||||||
transmission_in_progress((short) 8),
|
|
||||||
transmission_successful((short) 16),
|
|
||||||
transmission_failed((short) 32),
|
|
||||||
transmission_cancelled((short) 64),
|
|
||||||
;
|
|
||||||
|
|
||||||
final short value;
|
|
||||||
|
|
||||||
STATE(short value) {
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
short getValue() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addState(STATE state) {
|
|
||||||
this.state |= state.getValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeState(STATE state) {
|
|
||||||
this.state ^= state.getValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasState(STATE state) {
|
|
||||||
return (this.state & state.getValue()) == state.getValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
public JingleContent(JingleContentElement.Creator creator, JingleContentElement.Senders senders) {
|
public JingleContent(JingleContentElement.Creator creator, JingleContentElement.Senders senders) {
|
||||||
this(null, null, null, randomName(), null, creator, senders);
|
this(null, null, null, randomName(), null, creator, senders);
|
||||||
}
|
}
|
||||||
|
@ -114,7 +79,6 @@ public class JingleContent implements JingleTransportCallback, JingleSecurityCal
|
||||||
this.disposition = disposition;
|
this.disposition = disposition;
|
||||||
this.creator = creator;
|
this.creator = creator;
|
||||||
this.senders = senders;
|
this.senders = senders;
|
||||||
this.addState(STATE.pending_accept);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JingleContent fromElement(JingleContentElement content) {
|
public static JingleContent fromElement(JingleContentElement content) {
|
||||||
|
@ -226,7 +190,7 @@ public class JingleContent implements JingleTransportCallback, JingleSecurityCal
|
||||||
|
|
||||||
public IQ handleTransportAccept(JingleElement request, XMPPConnection connection) {
|
public IQ handleTransportAccept(JingleElement request, XMPPConnection connection) {
|
||||||
|
|
||||||
if (pendingReplacingTransport == null || !hasState(STATE.pending_transport_replace)) {
|
if (pendingReplacingTransport == null) {
|
||||||
LOGGER.log(Level.WARNING, "Received transport-accept, but apparently we did not try to replace the transport.");
|
LOGGER.log(Level.WARNING, "Received transport-accept, but apparently we did not try to replace the transport.");
|
||||||
return JingleElement.createJingleErrorOutOfOrder(request);
|
return JingleElement.createJingleErrorOutOfOrder(request);
|
||||||
}
|
}
|
||||||
|
@ -234,8 +198,6 @@ public class JingleContent implements JingleTransportCallback, JingleSecurityCal
|
||||||
transport = pendingReplacingTransport;
|
transport = pendingReplacingTransport;
|
||||||
pendingReplacingTransport = null;
|
pendingReplacingTransport = null;
|
||||||
|
|
||||||
removeState(STATE.pending_transport_replace);
|
|
||||||
|
|
||||||
onAccept(connection);
|
onAccept(connection);
|
||||||
|
|
||||||
return IQ.createResultIQ(request);
|
return IQ.createResultIQ(request);
|
||||||
|
@ -249,13 +211,12 @@ public class JingleContent implements JingleTransportCallback, JingleSecurityCal
|
||||||
}
|
}
|
||||||
|
|
||||||
public IQ handleTransportReject(JingleElement request, XMPPConnection connection) {
|
public IQ handleTransportReject(JingleElement request, XMPPConnection connection) {
|
||||||
removeState(STATE.pending_transport_replace);
|
|
||||||
return IQ.createResultIQ(request);
|
return IQ.createResultIQ(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IQ handleTransportReplace(final JingleElement request, final XMPPConnection connection) {
|
public IQ handleTransportReplace(final JingleElement request, final XMPPConnection connection) {
|
||||||
//Tie Break?
|
//Tie Break?
|
||||||
if (hasState(STATE.pending_transport_replace)) {
|
if (pendingReplacingTransport != null) {
|
||||||
Async.go(new Runnable() {
|
Async.go(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
@ -487,7 +448,7 @@ public class JingleContent implements JingleTransportCallback, JingleSecurityCal
|
||||||
private void replaceTransport(Set<String> blacklist, XMPPConnection connection)
|
private void replaceTransport(Set<String> blacklist, XMPPConnection connection)
|
||||||
throws SmackException.NotConnectedException, InterruptedException,
|
throws SmackException.NotConnectedException, InterruptedException,
|
||||||
XMPPException.XMPPErrorException, SmackException.NoResponseException {
|
XMPPException.XMPPErrorException, SmackException.NoResponseException {
|
||||||
if (hasState(STATE.pending_transport_replace)) {
|
if (pendingReplacingTransport != null) {
|
||||||
throw new AssertionError("Transport replace already pending.");
|
throw new AssertionError("Transport replace already pending.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -508,7 +469,6 @@ public class JingleContent implements JingleTransportCallback, JingleSecurityCal
|
||||||
session.getSessionId(), getCreator(), getName(), pendingReplacingTransport.getElement());
|
session.getSessionId(), getCreator(), getName(), pendingReplacingTransport.getElement());
|
||||||
|
|
||||||
connection.createStanzaCollectorAndSend(transportReplace).nextResultOrThrow();
|
connection.createStanzaCollectorAndSend(transportReplace).nextResultOrThrow();
|
||||||
addState(STATE.pending_transport_replace);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String randomName() {
|
public static String randomName() {
|
||||||
|
|
|
@ -65,8 +65,8 @@ public final class JingleS5BTransportManager extends Manager implements JingleTr
|
||||||
private List<Bytestream.StreamHost> localStreamHosts = null;
|
private List<Bytestream.StreamHost> localStreamHosts = null;
|
||||||
private List<Bytestream.StreamHost> availableStreamHosts = null;
|
private List<Bytestream.StreamHost> availableStreamHosts = null;
|
||||||
|
|
||||||
private static boolean useLocalCandidates = true;
|
public static boolean useLocalCandidates = true;
|
||||||
private static boolean useExternalCandidates = true;
|
public static boolean useExternalCandidates = true;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
JingleManager.addJingleTransportAdapter(new JingleS5BTransportAdapter());
|
JingleManager.addJingleTransportAdapter(new JingleS5BTransportAdapter());
|
||||||
|
|
|
@ -0,0 +1,180 @@
|
||||||
|
package org.jivesoftware.smackx.jft;
|
||||||
|
|
||||||
|
import static junit.framework.TestCase.fail;
|
||||||
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.SmackException;
|
||||||
|
import org.jivesoftware.smack.XMPPException;
|
||||||
|
import org.jivesoftware.smackx.bytestreams.socks5.Socks5Proxy;
|
||||||
|
import org.jivesoftware.smackx.jft.controller.IncomingFileOfferController;
|
||||||
|
import org.jivesoftware.smackx.jft.controller.OutgoingFileOfferController;
|
||||||
|
import org.jivesoftware.smackx.jft.listener.IncomingFileOfferListener;
|
||||||
|
import org.jivesoftware.smackx.jft.listener.ProgressListener;
|
||||||
|
import org.jivesoftware.smackx.jingle.transport.jingle_ibb.JingleIBBTransportManager;
|
||||||
|
import org.jivesoftware.smackx.jingle.transport.jingle_s5b.JingleS5BTransportManager;
|
||||||
|
|
||||||
|
import org.igniterealtime.smack.inttest.AbstractSmackIntegrationTest;
|
||||||
|
import org.igniterealtime.smack.inttest.SmackIntegrationTest;
|
||||||
|
import org.igniterealtime.smack.inttest.SmackIntegrationTestEnvironment;
|
||||||
|
import org.igniterealtime.smack.inttest.util.SimpleResultSyncPoint;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.jxmpp.jid.FullJid;
|
||||||
|
|
||||||
|
public class JingleFileTransferTransportFallbackTest extends AbstractSmackIntegrationTest {
|
||||||
|
|
||||||
|
private static final File tempDir;
|
||||||
|
|
||||||
|
static {
|
||||||
|
String userHome = System.getProperty("user.home");
|
||||||
|
if (userHome != null) {
|
||||||
|
File f = new File(userHome);
|
||||||
|
tempDir = new File(f, ".config/smack-integration-test/");
|
||||||
|
} else {
|
||||||
|
tempDir = new File("int_test_jingle");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public JingleFileTransferTransportFallbackTest(SmackIntegrationTestEnvironment environment) {
|
||||||
|
super(environment);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void crippleS5B() {
|
||||||
|
// Manipulate the Manager so that it'll fail.
|
||||||
|
JingleS5BTransportManager.useExternalCandidates = false;
|
||||||
|
JingleS5BTransportManager.useLocalCandidates = false;
|
||||||
|
// *evil super villain laughter*
|
||||||
|
}
|
||||||
|
|
||||||
|
@SmackIntegrationTest
|
||||||
|
public void S5BtoIBBfallbackTest() throws Exception {
|
||||||
|
|
||||||
|
JingleS5BTransportManager.getInstanceFor(conOne);
|
||||||
|
JingleS5BTransportManager.getInstanceFor(conTwo);
|
||||||
|
|
||||||
|
// Use Jingle IBB Transport as fallback.
|
||||||
|
JingleIBBTransportManager.getInstanceFor(conOne);
|
||||||
|
JingleIBBTransportManager.getInstanceFor(conTwo);
|
||||||
|
|
||||||
|
|
||||||
|
final SimpleResultSyncPoint resultSyncPoint1 = new SimpleResultSyncPoint();
|
||||||
|
final SimpleResultSyncPoint resultSyncPoint2 = new SimpleResultSyncPoint();
|
||||||
|
|
||||||
|
FullJid alice = conOne.getUser().asFullJidOrThrow();
|
||||||
|
FullJid bob = conTwo.getUser().asFullJidOrThrow();
|
||||||
|
|
||||||
|
File source = prepareNewTestFile("source");
|
||||||
|
final File target = new File(tempDir, "target");
|
||||||
|
|
||||||
|
JingleFileTransferManager aftm = JingleFileTransferManager.getInstanceFor(conOne);
|
||||||
|
JingleFileTransferManager bftm = JingleFileTransferManager.getInstanceFor(conTwo);
|
||||||
|
|
||||||
|
final ArrayList<Future<Void>> receiveFuture = new ArrayList<>(); //Uglaay
|
||||||
|
|
||||||
|
bftm.addIncomingFileOfferListener(new IncomingFileOfferListener() {
|
||||||
|
@Override
|
||||||
|
public void onIncomingFileOffer(IncomingFileOfferController offer) {
|
||||||
|
LOGGER.log(Level.INFO, "INCOMING FILE TRANSFER!");
|
||||||
|
|
||||||
|
offer.addProgressListener(new ProgressListener() {
|
||||||
|
@Override
|
||||||
|
public void started() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void progress(float percent) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finished() {
|
||||||
|
resultSyncPoint2.signal();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
receiveFuture.add(offer.accept(conTwo, target));
|
||||||
|
} catch (InterruptedException | XMPPException.XMPPErrorException | SmackException.NotConnectedException | SmackException.NoResponseException e) {
|
||||||
|
fail(e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
OutgoingFileOfferController sending = aftm.sendFile(source, bob);
|
||||||
|
|
||||||
|
sending.addProgressListener(new ProgressListener() {
|
||||||
|
@Override
|
||||||
|
public void started() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void progress(float percent) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finished() {
|
||||||
|
resultSyncPoint1.signal();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
resultSyncPoint1.waitForResult(60 * 1000);
|
||||||
|
resultSyncPoint2.waitForResult(60 * 1000);
|
||||||
|
|
||||||
|
byte[] sBytes = new byte[(int) source.length()];
|
||||||
|
byte[] tBytes = new byte[(int) target.length()];
|
||||||
|
try {
|
||||||
|
FileInputStream fi = new FileInputStream(source);
|
||||||
|
fi.read(sBytes);
|
||||||
|
fi.close();
|
||||||
|
fi = new FileInputStream(target);
|
||||||
|
fi.read(tBytes);
|
||||||
|
} catch (IOException e) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Could not read files.");
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
assertArrayEquals(sBytes, tBytes);
|
||||||
|
LOGGER.log(Level.INFO, "SUCCESSFULLY SENT AND RECEIVED");
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void cureS5B() {
|
||||||
|
JingleS5BTransportManager.useExternalCandidates = true;
|
||||||
|
JingleS5BTransportManager.useLocalCandidates = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static File prepareNewTestFile(String name) {
|
||||||
|
File testFile = new File(tempDir, name);
|
||||||
|
try {
|
||||||
|
if (!testFile.exists()) {
|
||||||
|
testFile.createNewFile();
|
||||||
|
}
|
||||||
|
FileOutputStream fo = new FileOutputStream(testFile);
|
||||||
|
byte[] rand = new byte[16000];
|
||||||
|
INSECURE_RANDOM.nextBytes(rand);
|
||||||
|
fo.write(rand);
|
||||||
|
fo.close();
|
||||||
|
return testFile;
|
||||||
|
} catch (IOException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public void cleanup() {
|
||||||
|
Socks5Proxy.getSocks5Proxy().stop();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue