From 136af25342864df3bc2f7ea98e2873aa4ec8a51e Mon Sep 17 00:00:00 2001 From: vanitasvitae Date: Fri, 23 Jun 2017 22:48:28 +0200 Subject: [PATCH] Add JingleTransportSession classes --- .../IncomingJingleFileOffer.java | 30 ++-- .../JingleFileRequest.java | 2 +- .../JingleFileTransferSession.java | 9 +- .../OutgoingJingleFileOffer.java | 26 ++-- .../bytestreams/socks5/Socks5Client.java | 2 +- .../smackx/jingle/FullJidAndSessionId.java | 8 + .../smackx/jingle/JingleManager.java | 5 +- .../smackx/jingle/JingleSession.java | 68 ++++----- .../jingle/JingleTransportMethodManager.java | 23 ++- .../transports/JingleTransportManager.java | 40 ++++- .../transports/JingleTransportNegotiator.java | 24 --- .../transports/JingleTransportSession.java | 67 +++++++++ .../jingle_ibb/JingleIBBTransportManager.java | 60 +------- .../jingle_ibb/JingleIBBTransportSession.java | 117 +++++++++++++++ .../jingle_s5b/JingleS5BTransportManager.java | 92 +++++------- .../jingle_s5b/JingleS5BTransportSession.java | 141 ++++++++++++++++++ .../smackx/jingle/JingleUtilTest.java | 102 +++++++++++++ 17 files changed, 584 insertions(+), 232 deletions(-) delete mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/JingleTransportNegotiator.java create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/JingleTransportSession.java create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_ibb/JingleIBBTransportSession.java create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_s5b/JingleS5BTransportSession.java create mode 100644 smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/JingleUtilTest.java diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/IncomingJingleFileOffer.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/IncomingJingleFileOffer.java index 6289945b0..6d5507bc7 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/IncomingJingleFileOffer.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/IncomingJingleFileOffer.java @@ -29,8 +29,8 @@ import org.jivesoftware.smackx.jingle.JingleTransportMethodManager; import org.jivesoftware.smackx.jingle.Role; import org.jivesoftware.smackx.jingle.element.Jingle; import org.jivesoftware.smackx.jingle.element.JingleContent; -import org.jivesoftware.smackx.jingle.element.JingleContentTransport; import org.jivesoftware.smackx.jingle.transports.JingleTransportInitiationCallback; +import org.jivesoftware.smackx.jingle.transports.JingleTransportManager; import org.jivesoftware.smackx.jingle_filetransfer.callback.IncomingFileOfferCallback; import org.jivesoftware.smackx.jingle_filetransfer.element.JingleFileTransfer; @@ -49,8 +49,7 @@ public class IncomingJingleFileOffer extends JingleFileTransferSession implement pending, sent_transport_replace, active, - terminated, - ; + terminated } private State state; @@ -78,9 +77,8 @@ public class IncomingJingleFileOffer extends JingleFileTransferSession implement this.creator = content.getCreator(); this.file = (JingleFileTransfer) content.getDescription(); this.name = content.getName(); - this.transport = content.getJingleTransport(); - this.transportManager = tm.getTransportManager(initiate); + JingleTransportManager transportManager = tm.getTransportManager(initiate); if (transportManager == null) { //Try fallback. pendingSessionInitiate = initiate; @@ -94,13 +92,16 @@ public class IncomingJingleFileOffer extends JingleFileTransferSession implement return jutil.createAck(initiate); } - transport = transportManager.createTransport(getInitiator()); + transportSession = transportManager.transportSession(this); jutil.sendTransportReplace(initiate.getFrom().asFullJidOrThrow(), initiate.getInitiator(), - initiate.getSid(), creator, name, transport); + initiate.getSid(), creator, name, transportSession.createTransport()); state = State.sent_transport_replace; return jutil.createAck(initiate); } + transportSession = transportManager.transportSession(this); + transportSession.setRemoteTransport(initiate.getContents().get(0).getJingleTransport()); + JingleFileTransferManager.getInstanceFor(connection).notifyIncomingFileOffer(initiate, this); state = State.pending; return jutil.createAck(initiate); @@ -115,15 +116,15 @@ public class IncomingJingleFileOffer extends JingleFileTransferSession implement } JingleFileTransferManager.getInstanceFor(connection).notifyIncomingFileOffer(pendingSessionInitiate, this); - transport = transportAccept.getContents().get(0).getJingleTransport(); + transportSession.setRemoteTransport(transportAccept.getContents().get(0).getJingleTransport()); state = State.pending; return jutil.createAck(transportAccept); } @Override - public void acceptIncomingFileOffer(Jingle request, final File target) { + public void acceptIncomingFileOffer(final Jingle request, final File target) { LOGGER.log(Level.INFO, "Client accepted incoming file offer. Try to start receiving."); - if (transportManager == null) { + if (transportSession == null) { //Unsupported transport LOGGER.log(Level.WARNING, "Unsupported Transport method."); try { @@ -134,13 +135,12 @@ public class IncomingJingleFileOffer extends JingleFileTransferSession implement return; } - final JingleContentTransport transport = transportManager.createTransport(request); - tasks.add(new Runnable() { + queued.add(threadPool.submit(new Runnable() { @Override public void run() { try { state = State.active; - transportManager.initiateIncomingSession(getInitiator(), transport, new JingleTransportInitiationCallback() { + transportSession.initiateIncomingSession(new JingleTransportInitiationCallback() { @Override public void onSessionInitiated(BytestreamSession bytestreamSession) { receivingThread = new ReceivingThread(bytestreamSession, file, target); @@ -152,12 +152,12 @@ public class IncomingJingleFileOffer extends JingleFileTransferSession implement } }); - jutil.sendSessionAccept(getInitiator(), sid, creator, name, JingleContent.Senders.initiator, file, transport); + jutil.sendSessionAccept(getInitiator(), sid, creator, name, JingleContent.Senders.initiator, file, transportSession.createTransport()); } catch (SmackException.NotConnectedException | SmackException.NoResponseException | XMPPException.XMPPErrorException | InterruptedException e) { LOGGER.log(Level.SEVERE, "Could not send session-accept: " + e, e); } } - }); + })); } @Override diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/JingleFileRequest.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/JingleFileRequest.java index 5f34d2908..01683e655 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/JingleFileRequest.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/JingleFileRequest.java @@ -34,7 +34,7 @@ public class JingleFileRequest extends JingleFileTransferSession { public static JingleFileRequest createOutgoingFileRequest(XMPPConnection connection, FullJid recipient) { return new JingleFileRequest(connection, connection.getUser().asFullJidOrThrow(), recipient, Role.initiator, - JingleManager.randomSid()); + JingleManager.randomId()); } public static JingleFileRequest createIncomingFileRequest(XMPPConnection connection, Jingle request) { diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/JingleFileTransferSession.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/JingleFileTransferSession.java index 5ccdeebd6..f7d82bf49 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/JingleFileTransferSession.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/JingleFileTransferSession.java @@ -21,8 +21,6 @@ import org.jivesoftware.smackx.jingle.JingleSession; import org.jivesoftware.smackx.jingle.JingleUtil; import org.jivesoftware.smackx.jingle.Role; import org.jivesoftware.smackx.jingle.element.JingleContent; -import org.jivesoftware.smackx.jingle.element.JingleContentTransport; -import org.jivesoftware.smackx.jingle.transports.JingleTransportManager; import org.jivesoftware.smackx.jingle_filetransfer.element.JingleFileTransfer; import org.jxmpp.jid.FullJid; @@ -44,8 +42,6 @@ public abstract class JingleFileTransferSession extends JingleSession { protected JingleContent.Creator creator; protected String name; protected JingleFileTransfer file; - protected JingleContentTransport transport; - protected JingleTransportManager transportManager; private final Type type; @@ -75,4 +71,9 @@ public abstract class JingleFileTransferSession extends JingleSession { public boolean isReceiver() { return (isRequest() && isInitiator()) || (isOffer() && isResponder()); } + + @Override + public XMPPConnection getConnection() { + return connection; + } } diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/OutgoingJingleFileOffer.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/OutgoingJingleFileOffer.java index 625ed5653..3b030eb6c 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/OutgoingJingleFileOffer.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/OutgoingJingleFileOffer.java @@ -48,8 +48,8 @@ public class OutgoingJingleFileOffer extends JingleFileTransferSession { pending, sent_transport_replace, active, - terminated, - ;} + terminated + } private Thread sendingThread; private File source; @@ -62,13 +62,13 @@ public class OutgoingJingleFileOffer extends JingleFileTransferSession { } public OutgoingJingleFileOffer(XMPPConnection connection, FullJid recipient) { - this(connection, recipient, JingleManager.randomSid()); + this(connection, recipient, JingleManager.randomId()); } public void send(File file) throws InterruptedException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, SmackException.NoResponseException { source = file; - String contentName = JingleManager.randomSid(); + String contentName = JingleManager.randomId(); JingleFileTransfer transfer = JingleFileTransferManager.fileTransferFromFile(file); initiateFileOffer(transfer, JingleContent.Creator.initiator, contentName); @@ -79,18 +79,18 @@ public class OutgoingJingleFileOffer extends JingleFileTransferSession { throw new IllegalStateException("This session is not fresh."); } - transportManager = JingleTransportMethodManager.getInstanceFor(connection) + JingleTransportManager transportManager = JingleTransportMethodManager.getInstanceFor(connection) .getBestAvailableTransportManager(); if (transportManager == null) { throw new IllegalStateException("There must be at least one workable transport method."); } - transport = transportManager.createTransport(getResponder()); + transportSession = transportManager.transportSession(this); state = State.pending; - jutil.sendSessionInitiateFileOffer(getResponder(), getSessionId(), creator, name, file, transport); + jutil.sendSessionInitiateFileOffer(getResponder(), getSessionId(), creator, name, file, transportSession.createTransport()); } @Override @@ -103,10 +103,10 @@ public class OutgoingJingleFileOffer extends JingleFileTransferSession { LOGGER.log(Level.INFO, "Session was accepted. Initiate Bytestream."); state = State.active; - tasks.add(new Runnable() { + queued.add(threadPool.submit(new Runnable() { @Override public void run() { - transportManager.initiateOutgoingSession(getResponder(), transport, new JingleTransportInitiationCallback() { + transportSession.initiateOutgoingSession(new JingleTransportInitiationCallback() { @Override public void onSessionInitiated(final BytestreamSession session) { LOGGER.log(Level.INFO, "BytestreamSession initiated. Start transfer."); @@ -120,7 +120,7 @@ public class OutgoingJingleFileOffer extends JingleFileTransferSession { } }); } - }); + })); return jutil.createAck(sessionAccept); } @@ -147,7 +147,7 @@ public class OutgoingJingleFileOffer extends JingleFileTransferSession { final JingleTransportManager replacementManager = JingleTransportMethodManager.getInstanceFor(connection) .getTransportManager(transportReplace); - tasks.add(new Runnable() { + queued.add(threadPool.submit(new Runnable() { @Override public void run() { try { @@ -155,7 +155,7 @@ public class OutgoingJingleFileOffer extends JingleFileTransferSession { LOGGER.log(Level.INFO, "Accept transport-replace."); jutil.sendTransportAccept(transportReplace.getFrom().asFullJidOrThrow(), transportReplace.getInitiator(), transportReplace.getSid(), creator, name, - replacementManager.createTransport(getResponder())); + transportSession.createTransport()); } else { LOGGER.log(Level.INFO, "Unsupported transport. Reject transport-replace."); jutil.sendTransportReject(transportReplace.getFrom().asFullJidOrThrow(), transportReplace.getInitiator(), @@ -165,7 +165,7 @@ public class OutgoingJingleFileOffer extends JingleFileTransferSession { LOGGER.log(Level.SEVERE, "Help me please!", e); } } - }); + })); return jutil.createAck(transportReplace); } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5Client.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5Client.java index 1c7b43670..15df6af4b 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5Client.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5Client.java @@ -46,7 +46,7 @@ import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream.StreamHost; * * @author Henning Staib */ -class Socks5Client { +public class Socks5Client { private static final Logger LOGGER = Logger.getLogger(Socks5Client.class.getName()); diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/FullJidAndSessionId.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/FullJidAndSessionId.java index 5d7a0d883..2bd3e7cde 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/FullJidAndSessionId.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/FullJidAndSessionId.java @@ -30,6 +30,14 @@ public class FullJidAndSessionId { this.sessionId = sessionId; } + public FullJid getFullJid() { + return fullJid; + } + + public String getSessionId() { + return sessionId; + } + @Override public int hashCode() { int hashCode = 31 * fullJid.hashCode(); 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 b4863c72c..9d26b689d 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 @@ -34,6 +34,7 @@ import org.jivesoftware.smackx.jingle.element.JingleAction; import org.jivesoftware.smackx.jingle.element.JingleContent; import org.jivesoftware.smackx.jingle.element.JingleContentDescription; import org.jivesoftware.smackx.jingle.transports.jingle_ibb.JingleIBBTransportManager; +import org.jivesoftware.smackx.jingle.transports.jingle_s5b.JingleS5BTransportManager; import org.jxmpp.jid.FullJid; @@ -102,7 +103,7 @@ public final class JingleManager extends Manager { //Register transports. JingleTransportMethodManager transportMethodManager = JingleTransportMethodManager.getInstanceFor(connection); transportMethodManager.registerTransportManager(JingleIBBTransportManager.getInstanceFor(connection)); - //transportMethodManager.registerTransportManager(JingleS5BTransportManager.getInstanceFor(connection)); + transportMethodManager.registerTransportManager(JingleS5BTransportManager.getInstanceFor(connection)); } public JingleHandler registerDescriptionHandler(String namespace, JingleHandler handler) { @@ -119,7 +120,7 @@ public final class JingleManager extends Manager { return jingleSessionHandlers.remove(fullJidAndSessionId); } - public static String randomSid() { + public static String randomId() { return StringUtils.randomString(24); } } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleSession.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleSession.java index b263387f1..b5955f32b 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleSession.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleSession.java @@ -16,14 +16,18 @@ */ package org.jivesoftware.smackx.jingle; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.logging.Level; +import java.util.ArrayList; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; import java.util.logging.Logger; import org.jivesoftware.smack.SmackException; +import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.packet.IQ; import org.jivesoftware.smackx.jingle.element.Jingle; +import org.jivesoftware.smackx.jingle.transports.JingleTransportSession; import org.jxmpp.jid.FullJid; @@ -38,38 +42,9 @@ public abstract class JingleSession implements JingleSessionHandler { protected final String sid; - protected final ConcurrentLinkedQueue tasks = new ConcurrentLinkedQueue() { - private static final long serialVersionUID = 1L; - - @Override - public boolean add(Runnable runnable) { - synchronized (tasks) { - LOGGER.log(Level.INFO, "Add task."); - boolean b = super.add(runnable); - tasks.notify(); - return b; - } - } - }; - - private final Thread worker = new Thread() { - @Override - public void run() { - synchronized (tasks) { - while (true) { - try { - tasks.wait(); - while (!tasks.isEmpty()) { - LOGGER.log(Level.INFO, "Run task."); - tasks.poll().run(); - } - } catch (InterruptedException e) { - LOGGER.log(Level.WARNING, "Interrupted."); - } - } - } - } - }; + protected ExecutorService threadPool = Executors.newSingleThreadExecutor(); + protected ArrayList> queued = new ArrayList<>(); + protected JingleTransportSession transportSession; public JingleSession(FullJid initiator, FullJid responder, Role role, String sid) { if (role == Role.initiator) { @@ -81,7 +56,6 @@ public abstract class JingleSession implements JingleSessionHandler { } this.sid = sid; this.role = role; - worker.start(); } public FullJid getInitiator() { @@ -100,6 +74,14 @@ public abstract class JingleSession implements JingleSessionHandler { return role == Role.responder; } + public FullJid getRemote() { + return remote; + } + + public FullJid getLocal() { + return local; + } + public String getSessionId() { return sid; } @@ -108,6 +90,14 @@ public abstract class JingleSession implements JingleSessionHandler { return new FullJidAndSessionId(remote, sid); } + public JingleTransportSession getTransportSession() { + return transportSession; + } + + protected void setTransportSession(JingleTransportSession transportSession) { + this.transportSession = transportSession; + } + @Override public int hashCode() { int hashCode = 31 + getInitiator().hashCode(); @@ -153,7 +143,7 @@ public abstract class JingleSession implements JingleSessionHandler { case transport_accept: return handleTransportAccept(jingle); case transport_info: - return handleTransportInfo(jingle); + return transportSession.handleTransportInfo(jingle); case session_initiate: return handleSessionInitiate(jingle); case transport_reject: @@ -218,10 +208,6 @@ public abstract class JingleSession implements JingleSessionHandler { return IQ.createResultIQ(transportAccept); } - protected IQ handleTransportInfo(Jingle transportInfo) { - return IQ.createResultIQ(transportInfo); - } - protected IQ handleTransportReplace(Jingle transportReplace) throws InterruptedException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, SmackException.NoResponseException { @@ -232,4 +218,6 @@ public abstract class JingleSession implements JingleSessionHandler { return IQ.createResultIQ(transportReject); } + public abstract XMPPConnection getConnection(); + } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleTransportMethodManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleTransportMethodManager.java index dea71d6ab..38b93a819 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleTransportMethodManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleTransportMethodManager.java @@ -36,14 +36,6 @@ public final class JingleTransportMethodManager extends Manager { private static final WeakHashMap INSTANCES = new WeakHashMap<>(); - static { - ClassLoader classLoader = JingleTransportMethodManager.class.getClassLoader(); - String[] knownTransports = new String[] { - "org.jivesoftware.smackx.jingle.transports.jingle_s5b.JingleS5BTransportManager", - "org.jivesoftware.smackx.jingle.transports.jingle_ibb.JingleIBBTransportManager" - }; - //TODO: Load dynamically. - } private final HashMap> transportManagers = new HashMap<>(); private static final String[] transportPreference = new String[] { @@ -68,10 +60,17 @@ public final class JingleTransportMethodManager extends Manager { transportManagers.put(manager.getNamespace(), manager); } + public static JingleTransportManager getTransportManager(XMPPConnection connection, String namespace) { + return getInstanceFor(connection).getTransportManager(namespace); + } + public JingleTransportManager getTransportManager(String namespace) { return transportManagers.get(namespace); } + public static JingleTransportManager getTransportManager(XMPPConnection connection, Jingle request) { + return getInstanceFor(connection).getTransportManager(request); + } public JingleTransportManager getTransportManager(Jingle request) { JingleContent content = request.getContents().get(0); @@ -87,10 +86,10 @@ public final class JingleTransportMethodManager extends Manager { return getTransportManager(transport.getNamespace()); } - /** - * TODO: Find better solution. - * @return - */ + public JingleTransportManager getBestAvailableTransportManager(XMPPConnection connection) { + return getInstanceFor(connection).getBestAvailableTransportManager(); + } + public JingleTransportManager getBestAvailableTransportManager() { JingleTransportManager tm; for (String ns : transportPreference) { diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/JingleTransportManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/JingleTransportManager.java index a4b7e563c..091fbeae6 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/JingleTransportManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/JingleTransportManager.java @@ -16,22 +16,22 @@ */ package org.jivesoftware.smackx.jingle.transports; +import org.jivesoftware.smack.ConnectionListener; import org.jivesoftware.smack.XMPPConnection; -import org.jivesoftware.smackx.jingle.element.Jingle; +import org.jivesoftware.smackx.jingle.JingleSession; import org.jivesoftware.smackx.jingle.element.JingleContentTransport; -import org.jxmpp.jid.FullJid; - /** * Manager for a JingleTransport method. * @param JingleContentTransport. */ -public abstract class JingleTransportManager { +public abstract class JingleTransportManager implements ConnectionListener { private final XMPPConnection connection; public JingleTransportManager(XMPPConnection connection) { this.connection = connection; + connection.addConnectionListener(this); } public XMPPConnection getConnection() { @@ -40,12 +40,36 @@ public abstract class JingleTransportManager { public abstract String getNamespace(); - public abstract D createTransport(FullJid recipient); + public abstract JingleTransportSession transportSession(JingleSession jingleSession); - public abstract D createTransport(Jingle request); - public abstract void initiateOutgoingSession(FullJid remote, JingleContentTransport transport, JingleTransportInitiationCallback callback); + @Override + public void connected(XMPPConnection connection) { - public abstract void initiateIncomingSession(FullJid remote, JingleContentTransport transport, JingleTransportInitiationCallback callback); + } + @Override + public void connectionClosed() { + + } + + @Override + public void connectionClosedOnError(Exception e) { + + } + + @Override + public void reconnectionSuccessful() { + + } + + @Override + public void reconnectingIn(int seconds) { + + } + + @Override + public void reconnectionFailed(Exception e) { + + } } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/JingleTransportNegotiator.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/JingleTransportNegotiator.java deleted file mode 100644 index 797897b92..000000000 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/JingleTransportNegotiator.java +++ /dev/null @@ -1,24 +0,0 @@ -/** - * - * Copyright 2017 Paul Schaub - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jivesoftware.smackx.jingle.transports; - -/** - * Created by vanitas on 20.06.17. - */ -public interface JingleTransportNegotiator { - -} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/JingleTransportSession.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/JingleTransportSession.java new file mode 100644 index 000000000..fdd3c0653 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/JingleTransportSession.java @@ -0,0 +1,67 @@ +/** + * + * Copyright 2017 Paul Schaub + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jivesoftware.smackx.jingle.transports; + +import java.lang.ref.WeakReference; + +import org.jivesoftware.smack.packet.IQ; +import org.jivesoftware.smackx.jingle.JingleSession; +import org.jivesoftware.smackx.jingle.element.Jingle; +import org.jivesoftware.smackx.jingle.element.JingleContent; +import org.jivesoftware.smackx.jingle.element.JingleContentTransport; + +/** + * Created by vanitas on 20.06.17. + */ +public abstract class JingleTransportSession { + protected final WeakReference jingleSession; + protected JingleContentTransport remoteTransport; + protected JingleContentTransport localTransport; + + public JingleTransportSession(JingleSession session) { + this.jingleSession = new WeakReference<>(session); + } + + public abstract T createTransport(); + + public void processJingle(Jingle jingle) { + if (jingle.getContents().size() == 0) { + return; + } + + JingleContent content = jingle.getContents().get(0); + JingleContentTransport t = content.getJingleTransport(); + + if (t != null && t.getNamespace().equals(getNamespace())) { + remoteTransport = t; + } + } + + public abstract void initiateOutgoingSession(JingleTransportInitiationCallback callback); + + public abstract void initiateIncomingSession(JingleTransportInitiationCallback callback); + + public abstract String getNamespace(); + + public abstract IQ handleTransportInfo(Jingle transportInfo); + + public void setRemoteTransport(JingleContentTransport remoteTransport) { + this.remoteTransport = remoteTransport; + } + + public abstract JingleTransportManager transportManager(); +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_ibb/JingleIBBTransportManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_ibb/JingleIBBTransportManager.java index bf93aa7b9..1c52512ec 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_ibb/JingleIBBTransportManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_ibb/JingleIBBTransportManager.java @@ -18,23 +18,14 @@ package org.jivesoftware.smackx.jingle.transports.jingle_ibb; import java.util.WeakHashMap; -import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.XMPPConnection; -import org.jivesoftware.smack.XMPPException; -import org.jivesoftware.smackx.bytestreams.BytestreamListener; -import org.jivesoftware.smackx.bytestreams.BytestreamRequest; -import org.jivesoftware.smackx.bytestreams.BytestreamSession; -import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager; -import org.jivesoftware.smackx.jingle.element.Jingle; -import org.jivesoftware.smackx.jingle.element.JingleContentTransport; +import org.jivesoftware.smackx.jingle.JingleSession; import org.jivesoftware.smackx.jingle.provider.JingleContentProviderManager; -import org.jivesoftware.smackx.jingle.transports.JingleTransportInitiationCallback; import org.jivesoftware.smackx.jingle.transports.JingleTransportManager; +import org.jivesoftware.smackx.jingle.transports.JingleTransportSession; import org.jivesoftware.smackx.jingle.transports.jingle_ibb.element.JingleIBBTransport; import org.jivesoftware.smackx.jingle.transports.jingle_ibb.provider.JingleIBBTransportProvider; -import org.jxmpp.jid.FullJid; - /** * Manager for Jingle InBandBytestream transports (XEP-0261). */ @@ -62,51 +53,12 @@ public final class JingleIBBTransportManager extends JingleTransportManager transportSession(JingleSession jingleSession) { + return new JingleIBBTransportSession(jingleSession); } @Override - public JingleIBBTransport createTransport(Jingle request) { - JingleIBBTransport rTransport = (JingleIBBTransport) request.getContents().get(0).getJingleTransport(); - return new JingleIBBTransport(rTransport.getBlockSize(), rTransport.getSessionId()); - } - - @Override - public void initiateOutgoingSession(FullJid remote, JingleContentTransport transport, JingleTransportInitiationCallback callback) { - JingleIBBTransport ibbTransport = (JingleIBBTransport) transport; - BytestreamSession session; - - try { - session = InBandBytestreamManager.getByteStreamManager(getConnection()) - .establishSession(remote, ibbTransport.getSessionId()); - callback.onSessionInitiated(session); - } catch (SmackException.NoResponseException | InterruptedException | SmackException.NotConnectedException | XMPPException.XMPPErrorException e) { - callback.onException(e); - } - } - - @Override - public void initiateIncomingSession(final FullJid remote, final JingleContentTransport transport, final JingleTransportInitiationCallback callback) { - final JingleIBBTransport ibbTransport = (JingleIBBTransport) transport; - - InBandBytestreamManager.getByteStreamManager(getConnection()).addIncomingBytestreamListener(new BytestreamListener() { - @Override - public void incomingBytestreamRequest(BytestreamRequest request) { - if (request.getFrom().asFullJidIfPossible().equals(remote) - && request.getSessionID().equals(ibbTransport.getSessionId())) { - - BytestreamSession session; - - try { - session = request.accept(); - } catch (InterruptedException | SmackException | XMPPException.XMPPErrorException e) { - callback.onException(e); - return; - } - callback.onSessionInitiated(session); - } - } - }); + public void authenticated(XMPPConnection connection, boolean resumed) { + //Nothing to do. } } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_ibb/JingleIBBTransportSession.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_ibb/JingleIBBTransportSession.java new file mode 100644 index 000000000..e4a3f9560 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_ibb/JingleIBBTransportSession.java @@ -0,0 +1,117 @@ +/** + * + * Copyright 2017 Paul Schaub + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jivesoftware.smackx.jingle.transports.jingle_ibb; + +import org.jivesoftware.smack.SmackException; +import org.jivesoftware.smack.XMPPException; +import org.jivesoftware.smack.packet.IQ; +import org.jivesoftware.smackx.bytestreams.BytestreamListener; +import org.jivesoftware.smackx.bytestreams.BytestreamRequest; +import org.jivesoftware.smackx.bytestreams.BytestreamSession; +import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager; +import org.jivesoftware.smackx.jingle.JingleSession; +import org.jivesoftware.smackx.jingle.element.Jingle; +import org.jivesoftware.smackx.jingle.transports.JingleTransportInitiationCallback; +import org.jivesoftware.smackx.jingle.transports.JingleTransportManager; +import org.jivesoftware.smackx.jingle.transports.JingleTransportSession; +import org.jivesoftware.smackx.jingle.transports.jingle_ibb.element.JingleIBBTransport; + +public class JingleIBBTransportSession extends JingleTransportSession { + + private final JingleIBBTransportManager transportManager; + + public JingleIBBTransportSession(JingleSession session) { + super(session); + transportManager = JingleIBBTransportManager.getInstanceFor(session.getConnection()); + } + + @Override + public JingleIBBTransport createTransport() { + + if (remoteTransport == null) { + return new JingleIBBTransport(); + } else { + JingleIBBTransport existing = (JingleIBBTransport) remoteTransport; + return new JingleIBBTransport(existing.getBlockSize(), existing.getSessionId()); + } + + } + + @Override + public void initiateOutgoingSession(JingleTransportInitiationCallback callback) { + if (jingleSession.get() == null) { + callback.onException(new NullPointerException("Lost reference to JingleSession.")); + return; + } + + JingleIBBTransport ibbTransport = (JingleIBBTransport) remoteTransport; + BytestreamSession session; + + try { + session = InBandBytestreamManager.getByteStreamManager(jingleSession.get().getConnection()) + .establishSession(jingleSession.get().getRemote(), ibbTransport.getSessionId()); + callback.onSessionInitiated(session); + } catch (SmackException.NoResponseException | InterruptedException | SmackException.NotConnectedException | XMPPException.XMPPErrorException e) { + callback.onException(e); + } + } + + @Override + public void initiateIncomingSession(final JingleTransportInitiationCallback callback) { + + if (jingleSession.get() == null) { + callback.onException(new NullPointerException("Lost reference to JingleSession.")); + } + + final JingleIBBTransport ibbTransport = (JingleIBBTransport) remoteTransport; + + InBandBytestreamManager.getByteStreamManager(jingleSession.get().getConnection()).addIncomingBytestreamListener(new BytestreamListener() { + @Override + public void incomingBytestreamRequest(BytestreamRequest request) { + if (request.getFrom().asFullJidIfPossible().equals(jingleSession.get().getRemote()) + && request.getSessionID().equals(ibbTransport.getSessionId())) { + + BytestreamSession session; + + try { + session = request.accept(); + } catch (InterruptedException | SmackException | XMPPException.XMPPErrorException e) { + callback.onException(e); + return; + } + callback.onSessionInitiated(session); + } + } + }); + } + + @Override + public String getNamespace() { + return transportManager.getNamespace(); + } + + @Override + public IQ handleTransportInfo(Jingle transportInfo) { + return IQ.createResultIQ(transportInfo); + //TODO + } + + @Override + public JingleTransportManager transportManager() { + return JingleIBBTransportManager.getInstanceFor(jingleSession.get().getConnection()); + } +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_s5b/JingleS5BTransportManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_s5b/JingleS5BTransportManager.java index ab74a5b20..fecff9f85 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_s5b/JingleS5BTransportManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_s5b/JingleS5BTransportManager.java @@ -17,7 +17,6 @@ package org.jivesoftware.smackx.jingle.transports.jingle_s5b; import java.util.ArrayList; -import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.WeakHashMap; @@ -29,19 +28,14 @@ import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.packet.IQ; import org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamManager; -import org.jivesoftware.smackx.bytestreams.socks5.Socks5Utils; import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream; -import org.jivesoftware.smackx.jingle.JingleManager; -import org.jivesoftware.smackx.jingle.element.Jingle; -import org.jivesoftware.smackx.jingle.element.JingleContentTransport; +import org.jivesoftware.smackx.jingle.JingleSession; import org.jivesoftware.smackx.jingle.provider.JingleContentProviderManager; -import org.jivesoftware.smackx.jingle.transports.JingleTransportInitiationCallback; import org.jivesoftware.smackx.jingle.transports.JingleTransportManager; +import org.jivesoftware.smackx.jingle.transports.JingleTransportSession; import org.jivesoftware.smackx.jingle.transports.jingle_s5b.elements.JingleS5BTransport; -import org.jivesoftware.smackx.jingle.transports.jingle_s5b.elements.JingleS5BTransportCandidate; import org.jivesoftware.smackx.jingle.transports.jingle_s5b.provider.JingleS5BTransportProvider; -import org.jxmpp.jid.FullJid; import org.jxmpp.jid.Jid; /** @@ -53,6 +47,9 @@ public final class JingleS5BTransportManager extends JingleTransportManager INSTANCES = new WeakHashMap<>(); + private List localStreamHosts = null; + private List availableStreamHosts = null; + private JingleS5BTransportManager(XMPPConnection connection) { super(connection); JingleContentProviderManager.addJingleContentTransportProvider(getNamespace(), new JingleS5BTransportProvider()); @@ -73,67 +70,35 @@ public final class JingleS5BTransportManager extends JingleTransportManager transportSession(JingleSession jingleSession) { + return new JingleS5BTransportSession(jingleSession); } - @Override - public JingleS5BTransport createTransport(Jingle request) { - FullJid remote = request.getFrom().asFullJidIfPossible(); - JingleS5BTransport received = (JingleS5BTransport) request.getContents().get(0).getJingleTransport(); - - return createTransport(remote, received.getStreamId(), received.getMode()); - } - - private JingleS5BTransport createTransport(FullJid remote, String sid, Bytestream.Mode mode) { - JingleS5BTransport.Builder builder = JingleS5BTransport.getBuilder(); - List localStreams = getLocalStreamHosts(); - List availableStreams; - try { - availableStreams = getAvailableStreamHosts(); - } catch (XMPPException.XMPPErrorException | SmackException.NoResponseException | InterruptedException | SmackException.NotConnectedException e) { - LOGGER.log(Level.WARNING, "Could not determine available StreamHosts: ", e); - availableStreams = Collections.emptyList(); - } - - for (Bytestream.StreamHost host : localStreams) { - JingleS5BTransportCandidate candidate = new JingleS5BTransportCandidate(host, 100); - builder.addTransportCandidate(candidate); - } - - for (Bytestream.StreamHost host : availableStreams) { - JingleS5BTransportCandidate candidate = new JingleS5BTransportCandidate(host, 0); - builder.addTransportCandidate(candidate); - } - - builder.setStreamId(sid); - builder.setMode(mode); - builder.setDestinationAddress(Socks5Utils.createDigest(sid, getConnection().getUser().asFullJidOrThrow(), remote)); - return builder.build(); - } - - - @Override - public void initiateOutgoingSession(FullJid remote, JingleContentTransport transport, JingleTransportInitiationCallback callback) { - - } - - @Override - public void initiateIncomingSession(FullJid remote, JingleContentTransport transport, JingleTransportInitiationCallback callback) { - - } - - public List getAvailableStreamHosts() throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException { + private List queryAvailableStreamHosts() throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException { Socks5BytestreamManager s5m = Socks5BytestreamManager.getBytestreamManager(getConnection()); List proxies = s5m.determineProxies(); return determineStreamHostInfo(proxies); } - public List getLocalStreamHosts() { + private List queryLocalStreamHosts() { return Socks5BytestreamManager.getBytestreamManager(getConnection()) .getLocalStreamHost(); } + public List getAvailableStreamHosts() throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException { + if (availableStreamHosts == null) { + availableStreamHosts = queryAvailableStreamHosts(); + } + return availableStreamHosts; + } + + public List getLocalStreamHosts() { + if (localStreamHosts == null) { + localStreamHosts = queryLocalStreamHosts(); + } + return localStreamHosts; + } + public List determineStreamHostInfo(List proxies) { XMPPConnection connection = getConnection(); List streamHosts = new ArrayList<>(); @@ -155,4 +120,15 @@ public final class JingleS5BTransportManager extends JingleTransportManager { + private static final Logger LOGGER = Logger.getLogger(JingleS5BTransportSession.class.getName()); + private final JingleS5BTransportManager transportManager; + + public JingleS5BTransportSession(JingleSession jingleSession) { + super(jingleSession); + transportManager = JingleS5BTransportManager.getInstanceFor(jingleSession.getConnection()); + } + + @Override + public JingleS5BTransport createTransport() { + if (localTransport != null) { + return (JingleS5BTransport) localTransport; + } + + return createTransport(JingleManager.randomId(), Bytestream.Mode.tcp); + } + + private JingleS5BTransport createTransport(String sid, Bytestream.Mode mode) { + JingleS5BTransport.Builder builder = JingleS5BTransport.getBuilder(); + + for (Bytestream.StreamHost host : transportManager.getLocalStreamHosts()) { + JingleS5BTransportCandidate candidate = new JingleS5BTransportCandidate(host, 100); + builder.addTransportCandidate(candidate); + } + + List availableStreamHosts = null; + + try { + availableStreamHosts = transportManager.getAvailableStreamHosts(); + } catch (XMPPException.XMPPErrorException | SmackException.NoResponseException | InterruptedException | SmackException.NotConnectedException e) { + LOGGER.log(Level.WARNING, "Could not get available StreamHosts: " + e, e); + } + + for (Bytestream.StreamHost host : availableStreamHosts != null ? + availableStreamHosts : Collections.emptyList()) { + JingleS5BTransportCandidate candidate = new JingleS5BTransportCandidate(host, 0); + builder.addTransportCandidate(candidate); + } + + builder.setStreamId(sid); + builder.setMode(mode); + builder.setDestinationAddress(Socks5Utils.createDigest(sid, jingleSession.get().getLocal(), jingleSession.get().getRemote())); + return builder.build(); + } + + @Override + public void initiateOutgoingSession(JingleTransportInitiationCallback callback) { + JingleS5BTransport receivedTransport = (JingleS5BTransport) remoteTransport; + + Socket socket = null; + JingleS5BTransportCandidate workedForUs = null; + + for (JingleContentTransportCandidate c : receivedTransport.getCandidates()) { + JingleS5BTransportCandidate candidate = (JingleS5BTransportCandidate) c; + Bytestream.StreamHost streamHost = candidate.getStreamHost(); + + String address = streamHost.getAddress(); + + try { + Socks5Client socks5Client = new Socks5Client(streamHost, receivedTransport.getDestinationAddress()); + socket = socks5Client.getSocket(10 * 1000); + workedForUs = candidate; + + } catch (IOException | XMPPException | InterruptedException | TimeoutException | SmackException e) { + LOGGER.log(Level.WARNING, "Could not connect to remotes address " + address + " with dstAddr " + + receivedTransport.getDestinationAddress()); + } + + if (socket != null) { + + } + } + } + + @Override + public void initiateIncomingSession(JingleTransportInitiationCallback callback) { + + } + + @Override + public String getNamespace() { + return transportManager.getNamespace(); + } + + @Override + public IQ handleTransportInfo(Jingle transportInfo) { + return null; + } + + @Override + public JingleTransportManager transportManager() { + return JingleS5BTransportManager.getInstanceFor(jingleSession.get().getConnection()); + } + +} diff --git a/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/JingleUtilTest.java b/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/JingleUtilTest.java new file mode 100644 index 000000000..500ee2279 --- /dev/null +++ b/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/JingleUtilTest.java @@ -0,0 +1,102 @@ +/** + * + * Copyright 2017 Paul Schaub + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jivesoftware.smackx.jingle; + +import org.jivesoftware.smack.DummyConnection; +import org.jivesoftware.smack.XMPPConnection; +import org.jivesoftware.smack.test.util.SmackTestSuite; +import org.jivesoftware.smackx.jingle.element.Jingle; +import org.jivesoftware.smackx.jingle.element.JingleContent; + +import org.junit.Before; +import org.junit.Test; +import org.jxmpp.jid.FullJid; +import org.jxmpp.jid.impl.JidCreate; +import org.jxmpp.stringprep.XmppStringprepException; + +/** + * Test the JingleUtil class. + */ +public class JingleUtilTest extends SmackTestSuite { + + private XMPPConnection connection; + private JingleUtil jutil; + + @Before + public void setup() { + connection = new DummyConnection( + DummyConnection.getDummyConfigurationBuilder() + .setUsernameAndPassword("romeo@montague.lit", + "iluvJulibabe13").build()); + jutil = new JingleUtil(connection); + } + + @Test + public void sessionInitiateTest() throws XmppStringprepException { + FullJid romeo = connection.getUser().asFullJidOrThrow(); + FullJid juliet = JidCreate.fullFrom("juliet@capulet.example/yn0cl4bnw0yr3vym"); + + String sid = "851ba2"; + String contentName = "a-file-offer"; + Jingle jingle = jutil.createSessionInitiate(juliet, sid, + JingleContent.Creator.initiator, contentName, JingleContent.Senders.initiator, null, null); + + + + String expected = + "" + + "" + + "" + + "" + + "" + + "1969-07-21T02:56:15Z" + + "This is a test. If this were a real file..." + + "text/plain" + + "test.txt" + + "" + + "6144" + + "w0mcJylzCn+AfvuGdqkty2+KP48=" + + "" + + "" + + " " + + "" + + "" + + "" + + "" + + "" + + ""; + } +}