diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleManager.java index d84ca8cb9..d2812758c 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleManager.java @@ -71,9 +71,7 @@ public final class JingleManager extends Manager { private final ConcurrentHashMap jingleSessions = new ConcurrentHashMap<>(); - public static boolean ALLOW_MULTIPLE_CONTENT_PER_SESSION = false; - - private JingleManager(XMPPConnection connection) { + private JingleManager(final XMPPConnection connection) { super(connection); connection.registerIQRequestHandler( @@ -91,7 +89,7 @@ public final class JingleManager extends Manager { // We have not seen this session before. // Either it is fresh, or unknown. if (session == null) { - + LOGGER.log(Level.INFO, connection().getUser().asFullJidOrThrow() + " received unknown session: " + jingle.getFrom().asFullJidOrThrow() + " " + jingle.getSid()); if (jingle.getAction() == JingleAction.session_initiate) { //fresh. phew! try { @@ -266,6 +264,12 @@ public final class JingleManager extends Manager { return session; } + public void addSession(JingleSession session) { + if (!jingleSessions.containsValue(session)) { + jingleSessions.put(new FullJidAndSessionId(session.getPeer(), session.getSessionId()), session); + } + } + public void removeSession(JingleSession session) { jingleSessions.remove(new FullJidAndSessionId(session.getPeer(), session.getSessionId())); } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/components/JingleTransport.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/components/JingleTransport.java index 72b8d83e5..117ea37f9 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/components/JingleTransport.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/components/JingleTransport.java @@ -18,6 +18,8 @@ package org.jivesoftware.smackx.jingle.components; import java.util.ArrayList; import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.SmackFuture; @@ -34,6 +36,8 @@ import org.jivesoftware.smackx.jingle.element.JingleElement; */ public abstract class JingleTransport extends SmackFuture { + private static final Logger LOGGER = Logger.getLogger(JingleTransport.class.getName()); + private JingleContent parent; private final ArrayList> candidates = new ArrayList<>(); @@ -45,6 +49,7 @@ public abstract class JingleTransport e public abstract D getElement(); public void addCandidate(JingleTransportCandidate candidate) { + LOGGER.log(Level.INFO, "Insert candidate."); // Insert sorted by descending priority // Empty list -> insert @@ -59,7 +64,7 @@ public abstract class JingleTransport e JingleTransportCandidate c = candidates.get(i); // list already contains element -> return - if (c == candidate) { + if (c == candidate || c.equals(candidate)) { return; } @@ -67,6 +72,7 @@ public abstract class JingleTransport e if (c.getPriority() <= candidate.getPriority()) { candidates.add(i, candidate); candidate.setParent(this); + return; } } } @@ -85,6 +91,7 @@ public abstract class JingleTransport e public void setPeersProposal(JingleTransport peersProposal) { this.peersProposal = peersProposal; + peersProposal.setParent(getParent()); peersProposal.isPeersProposal = true; } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/JingleS5BTransport.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/JingleS5BTransport.java index 8508e48d3..33431dc7a 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/JingleS5BTransport.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/JingleS5BTransport.java @@ -83,6 +83,7 @@ public class JingleS5BTransport extends JingleTransport> candidates) { @@ -96,6 +97,10 @@ public class JingleS5BTransport extends JingleTransport c : getCandidates()) { + for (JingleTransportCandidate c : getPeersProposal().getCandidates()) { int _timeout = timeout / getCandidates().size(); //TODO: Wise? try { - return ((JingleS5BTransportCandidate) c).connect(_timeout); + return ((JingleS5BTransportCandidate) c).connect(_timeout, true); } catch (IOException | TimeoutException | InterruptedException | SmackException | XMPPException e) { LOGGER.log(Level.WARNING, "Exception while connecting to candidate: " + e, e); } @@ -179,7 +184,7 @@ public class JingleS5BTransport extends JingleTransport out-of-order! if (peers.getSelectedCandidate() != null) { try { - jingleManager.getConnection().createStanzaCollectorAndSend(JingleElement.createJingleErrorOutOfOrder(wrapping)); + jingleManager.getConnection().sendStanza(JingleElement.createJingleErrorOutOfOrder(wrapping)); + //jingleManager.getConnection().createStanzaCollectorAndSend(JingleElement.createJingleErrorOutOfOrder(wrapping)); } catch (SmackException.NotConnectedException | InterruptedException e) { LOGGER.log(Level.SEVERE, "Could not respond to candidate-used transport-info: " + e, e); } @@ -320,12 +326,14 @@ public class JingleS5BTransport extends JingleTransport> ourCandidates = getCandidates().iterator(); while (ourCandidates.hasNext()) { JingleS5BTransportCandidate candidate = (JingleS5BTransportCandidate) ourCandidates.next(); + LOGGER.log(Level.INFO, "CandidateID: " + candidate.getCandidateId() + " " + candidateId); if (candidate.getCandidateId().equals(candidateId)) { peers.setSelectedCandidate(candidate); } } if (peers.getSelectedCandidate() == null) { + LOGGER.log(Level.SEVERE, "ILLEGAL CANDIDATE ID!!!"); //TODO: Alert! Illegal candidateId! } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/JingleS5BTransportCandidate.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/JingleS5BTransportCandidate.java index 1c8b3c265..07b3bbed0 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/JingleS5BTransportCandidate.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/JingleS5BTransportCandidate.java @@ -19,13 +19,17 @@ package org.jivesoftware.smackx.jingle.transport.jingle_s5b; import java.io.IOException; import java.net.Socket; import java.util.concurrent.TimeoutException; +import java.util.logging.Level; +import java.util.logging.Logger; import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smackx.bytestreams.socks5.Socks5Client; import org.jivesoftware.smackx.bytestreams.socks5.Socks5ClientForInitiator; import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream; +import org.jivesoftware.smackx.jingle.components.JingleContent; import org.jivesoftware.smackx.jingle.components.JingleSession; +import org.jivesoftware.smackx.jingle.components.JingleTransport; import org.jivesoftware.smackx.jingle.components.JingleTransportCandidate; import org.jivesoftware.smackx.jingle.transport.jingle_s5b.element.JingleS5BTransportCandidateElement; @@ -33,6 +37,7 @@ import org.jivesoftware.smackx.jingle.transport.jingle_s5b.element.JingleS5BTran * Jingle SOCKS5Bytestream transport candidate. */ public class JingleS5BTransportCandidate extends JingleTransportCandidate { + private static final Logger LOGGER = Logger.getLogger(JingleS5BTransportCandidate.class.getName()); private final String candidateId; private final Bytestream.StreamHost streamHost; @@ -75,16 +80,20 @@ public class JingleS5BTransportCandidate extends JingleTransportCandidate transport = getParent(); + JingleContent content = transport.getParent(); + JingleSession session = content.getParent(); client = new Socks5ClientForInitiator(getStreamHost(), ((JingleS5BTransport) getParent()).getDstAddr(), - session.getJingleManager().getConnection(), session.getSessionId(), session.getPeer()); + session.getJingleManager().getConnection(), ((JingleS5BTransport) getParent()).getSid(), getStreamHost().getJID()); } this.socket = client.getSocket(timeout); diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/JingleS5BTransportManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/JingleS5BTransportManager.java index 8c829c8dd..edb2b6fd9 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/JingleS5BTransportManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/JingleS5BTransportManager.java @@ -137,6 +137,8 @@ public final class JingleS5BTransportManager extends Manager implements JingleTr candidates.add(new JingleS5BTransportCandidate(StringUtils.randomString(16), host, 0, JingleS5BTransportCandidateElement.Type.proxy)); } + LOGGER.log(Level.INFO, "Collected candidates."); + return candidates; } @@ -191,9 +193,14 @@ public final class JingleS5BTransportManager extends Manager implements JingleTr JingleElement.Builder jb = JingleElement.getBuilder() .setSessionId(session.getSessionId()) - .setInitiator(session.getInitiator()) .setAction(JingleAction.transport_info); + if (session.isInitiator()) { + jb.setInitiator(session.getInitiator()); + } else { + jb.setResponder(session.getResponder()); + } + JingleContentElement.Builder cb = JingleContentElement.getBuilder() .setCreator(content.getCreator()) .setName(content.getName()) diff --git a/smack-integration-test/src/main/java/org/jivesoftware/smackx/jingle/transport/JingleTransportTest.java b/smack-integration-test/src/main/java/org/jivesoftware/smackx/jingle/transport/JingleTransportTest.java index 4fa280164..d13000dca 100644 --- a/smack-integration-test/src/main/java/org/jivesoftware/smackx/jingle/transport/JingleTransportTest.java +++ b/smack-integration-test/src/main/java/org/jivesoftware/smackx/jingle/transport/JingleTransportTest.java @@ -24,8 +24,10 @@ import java.io.OutputStream; import java.util.Random; import java.util.logging.Level; +import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.util.Async; import org.jivesoftware.smackx.bytestreams.BytestreamSession; +import org.jivesoftware.smackx.bytestreams.socks5.Socks5Proxy; import org.jivesoftware.smackx.jingle.JingleManager; import org.jivesoftware.smackx.jingle.callbacks.JingleTransportCallback; import org.jivesoftware.smackx.jingle.components.JingleContent; @@ -41,7 +43,9 @@ 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.Assert; +import org.junit.Before; /** * Test the JingleIBBTransport in a very basic case. @@ -52,33 +56,52 @@ public class JingleTransportTest extends AbstractSmackIntegrationTest { super(environment); } + @Before + public void setup() { + Socks5Proxy socks5Proxy = Socks5Proxy.getSocks5Proxy(); + if (!socks5Proxy.isRunning()) { + socks5Proxy.start(); + } + } + @SmackIntegrationTest public void JingleIBBTest() throws Exception { - JingleIBBTransport sender = new JingleIBBTransport(); - final JingleIBBTransport receiver = new JingleIBBTransport(sender.getSid(), sender.getBlockSize()); + JingleIBBTransport sTransport = new JingleIBBTransport(); + final JingleIBBTransport rTransport = new JingleIBBTransport(sTransport.getSid(), sTransport.getBlockSize()); - basicTransportTest(sender, receiver); + JingleSession sSession = new JingleSession(JingleManager.getInstanceFor(conOne), conOne.getUser().asFullJidOrThrow(), conTwo.getUser().asFullJidOrThrow(), Role.initiator, "session"); + JingleSession rSession = new JingleSession(JingleManager.getInstanceFor(conTwo), conOne.getUser().asFullJidOrThrow(), conTwo.getUser().asFullJidOrThrow(), Role.responder, "session"); + + basicTransportTest(sSession, rSession, sTransport, rTransport); } @SmackIntegrationTest public void JingleS5BTest() throws Exception { - JingleSession sSession = new JingleSession(JingleManager.getInstanceFor(conOne), conOne.getUser().asFullJidOrThrow(), conTwo.getUser().asFullJidOrThrow(), Role.initiator, "session"); - JingleSession rSession = new JingleSession(JingleManager.getInstanceFor(conTwo), conTwo.getUser().asFullJidOrThrow(), conOne.getUser().asFullJidOrThrow(), Role.responder, "session"); + XMPPConnection sender = conOne; + XMPPConnection receiver = conTwo; + JingleSession sSession = new JingleSession(JingleManager.getInstanceFor(sender), sender.getUser().asFullJidOrThrow(), receiver.getUser().asFullJidOrThrow(), Role.initiator, "session"); + JingleSession rSession = new JingleSession(JingleManager.getInstanceFor(receiver), sender.getUser().asFullJidOrThrow(), receiver.getUser().asFullJidOrThrow(), Role.responder, "session"); + LOGGER.log(Level.INFO, sender.getUser().asFullJidOrThrow() + " adds " + sSession.getPeer() + " " + sSession.getSessionId()); + JingleManager.getInstanceFor(sender).addSession(sSession); + LOGGER.log(Level.INFO, receiver.getUser().asFullJidOrThrow() + " adds " + rSession.getPeer() + " " + rSession.getSessionId()); + JingleManager.getInstanceFor(receiver).addSession(rSession); + JingleContent sContent = new JingleContent(null, null, null, "content", null, JingleContentElement.Creator.initiator, JingleContentElement.Senders.initiator); JingleContent rContent = new JingleContent(null, null, null, "content", null, JingleContentElement.Creator.initiator, JingleContentElement.Senders.initiator); sSession.addContent(sContent); rSession.addContent(rContent); - JingleS5BTransport sender = (JingleS5BTransport) JingleS5BTransportManager.getInstanceFor(conOne).createTransport(sContent); - JingleS5BTransport receiver = (JingleS5BTransport) JingleS5BTransportManager.getInstanceFor(conTwo).createTransport(rContent, sender); + JingleS5BTransport sTransport = (JingleS5BTransport) JingleS5BTransportManager.getInstanceFor(sender).createTransport(sContent); + JingleS5BTransport rTransport = (JingleS5BTransport) JingleS5BTransportManager.getInstanceFor(receiver).createTransport(rContent, sTransport); + sContent.setTransport(sTransport); + rContent.setTransport(rTransport); + sTransport.setPeersProposal(new JingleS5BTransport(rTransport)); + rTransport.setPeersProposal(new JingleS5BTransport(sTransport)); - basicTransportTest(sender, receiver); + basicTransportTest(sSession, rSession, sTransport, rTransport); } - public void basicTransportTest(final JingleTransport sender, final JingleTransport receiver) throws Exception { - JingleSession senderSession = new JingleSession(null, conTwo.getUser().asFullJidOrThrow(), conOne.getUser().asFullJidOrThrow(), Role.initiator, "sid"); - JingleSession receiverSession = new JingleSession(null, conTwo.getUser().asFullJidOrThrow(), conOne.getUser().asFullJidOrThrow(), Role.responder, "sid"); - + public void basicTransportTest(JingleSession sSession, JingleSession rSession, final JingleTransport sTransport, final JingleTransport rTransport) throws Exception { final SimpleResultSyncPoint recvPoint = new SimpleResultSyncPoint(); final int size = 16000; @@ -86,7 +109,7 @@ public class JingleTransportTest extends AbstractSmackIntegrationTest { new Random().nextBytes(data); final byte[] recv = new byte[size]; - receiver.establishIncomingBytestreamSession(conOne, new JingleTransportCallback() { + rTransport.establishIncomingBytestreamSession(rSession.getJingleManager().getConnection(), new JingleTransportCallback() { @Override public void onTransportReady(final BytestreamSession bytestreamSession) { LOGGER.log(Level.INFO, "Receiving!"); @@ -106,6 +129,7 @@ public class JingleTransportTest extends AbstractSmackIntegrationTest { } else { break; } + LOGGER.log(Level.INFO, "Read " + r + " bytes (" + read + " of " + size + ")"); } LOGGER.log(Level.INFO, "Success!"); @@ -124,9 +148,9 @@ public class JingleTransportTest extends AbstractSmackIntegrationTest { LOGGER.log(Level.SEVERE, e.toString()); recvPoint.signal(); } - }, receiverSession); + }, rSession); - sender.establishOutgoingBytestreamSession(conTwo, new JingleTransportCallback() { + sTransport.establishOutgoingBytestreamSession(sSession.getJingleManager().getConnection(), new JingleTransportCallback() { @Override public void onTransportReady(final BytestreamSession bytestreamSession) { LOGGER.log(Level.INFO, "Sending!"); @@ -141,6 +165,7 @@ public class JingleTransportTest extends AbstractSmackIntegrationTest { } catch (IOException e) { fail(e.toString()); } + LOGGER.log(Level.INFO, "Sending finished!"); } }); } @@ -149,9 +174,19 @@ public class JingleTransportTest extends AbstractSmackIntegrationTest { public void onTransportFailed(Exception e) { LOGGER.log(Level.SEVERE, e.toString()); } - }, senderSession); + }, sSession); recvPoint.waitForResult(60 * 1000); Assert.assertArrayEquals(data, recv); + sSession.getJingleManager().removeSession(sSession); + rSession.getJingleManager().removeSession(rSession); + } + + @After + public void tearDown() { + Socks5Proxy socks5Proxy = Socks5Proxy.getSocks5Proxy(); + if (socks5Proxy.isRunning()) { + socks5Proxy.stop(); + } } }