From 5f1d2a7f20a347cee9ec57876ae816f39bd4e1d6 Mon Sep 17 00:00:00 2001 From: vanitasvitae Date: Fri, 25 Aug 2017 19:04:52 +0200 Subject: [PATCH] Add javadoc --- .../adapter/JingleDescriptionAdapter.java | 2 +- .../jingle/adapter/JingleSecurityAdapter.java | 2 +- .../adapter/JingleTransportAdapter.java | 2 +- .../smackx/jingle/adapter/package-info.java | 2 +- .../JingleSecurityCallback.java | 2 +- .../JingleTransportCallback.java | 12 +- .../{callbacks => callback}/package-info.java | 2 +- .../jingle/component/JingleContent.java | 208 +++++++++++++++++- .../jingle/component/JingleDescription.java | 32 +++ .../jingle/component/JingleSecurity.java | 50 ++++- .../JingleSecurityBytestreamSession.java | 17 +- .../jingle/component/JingleSession.java | 201 ++++++++++++++++- .../jingle/component/JingleTransport.java | 87 +++++++- .../component/JingleTransportCandidate.java | 27 +++ .../jingle_ibb/JingleIBBTransport.java | 2 +- .../jingle_s5b/JingleS5BTransport.java | 2 +- .../JingleTransportIntegrationTest.java | 2 +- 17 files changed, 623 insertions(+), 29 deletions(-) rename smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/{callbacks => callback}/JingleSecurityCallback.java (94%) rename smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/{callbacks => callback}/JingleTransportCallback.java (64%) rename smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/{callbacks => callback}/package-info.java (93%) diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/adapter/JingleDescriptionAdapter.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/adapter/JingleDescriptionAdapter.java index 5d9aa4bdd..239ff556d 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/adapter/JingleDescriptionAdapter.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/adapter/JingleDescriptionAdapter.java @@ -21,7 +21,7 @@ import org.jivesoftware.smackx.jingle.element.JingleContentDescriptionElement; import org.jivesoftware.smackx.jingle.element.JingleContentElement; /** - * Adapter that creates a Description object from an element. + * Adapter that creates a {@link JingleDescription} object from a {@link JingleContentDescriptionElement}. */ public interface JingleDescriptionAdapter> { diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/adapter/JingleSecurityAdapter.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/adapter/JingleSecurityAdapter.java index 683049919..c4b958011 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/adapter/JingleSecurityAdapter.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/adapter/JingleSecurityAdapter.java @@ -20,7 +20,7 @@ import org.jivesoftware.smackx.jingle.component.JingleSecurity; import org.jivesoftware.smackx.jingle.element.JingleContentSecurityElement; /** - * Adapter that creates a Security object from an element. + * Adapter that creates a {@link JingleSecurity} object from a {@link JingleContentSecurityElement}. */ public interface JingleSecurityAdapter> { diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/adapter/JingleTransportAdapter.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/adapter/JingleTransportAdapter.java index 4a550ceea..6f6d49012 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/adapter/JingleTransportAdapter.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/adapter/JingleTransportAdapter.java @@ -20,7 +20,7 @@ import org.jivesoftware.smackx.jingle.component.JingleTransport; import org.jivesoftware.smackx.jingle.element.JingleContentTransportElement; /** - * Adapter that creates a Transport element from an element. + * Adapter that creates a {@link JingleTransport} element from a {@link JingleContentTransportElement}. */ public interface JingleTransportAdapter> { diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/adapter/package-info.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/adapter/package-info.java index 672be8d4c..76bf010de 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/adapter/package-info.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/adapter/package-info.java @@ -17,6 +17,6 @@ /** * Smack's API for XEP-0166: Jingle. - * Adapters. + * Content adapters. */ package org.jivesoftware.smackx.jingle.adapter; diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/callbacks/JingleSecurityCallback.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/callback/JingleSecurityCallback.java similarity index 94% rename from smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/callbacks/JingleSecurityCallback.java rename to smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/callback/JingleSecurityCallback.java index afcd9d141..5a23d64a8 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/callbacks/JingleSecurityCallback.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/callback/JingleSecurityCallback.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jivesoftware.smackx.jingle.callbacks; +package org.jivesoftware.smackx.jingle.callback; import org.jivesoftware.smackx.bytestreams.BytestreamSession; diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/callbacks/JingleTransportCallback.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/callback/JingleTransportCallback.java similarity index 64% rename from smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/callbacks/JingleTransportCallback.java rename to smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/callback/JingleTransportCallback.java index 2cb3405e9..6e4ed535e 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/callbacks/JingleTransportCallback.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/callback/JingleTransportCallback.java @@ -14,16 +14,24 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jivesoftware.smackx.jingle.callbacks; +package org.jivesoftware.smackx.jingle.callback; import org.jivesoftware.smackx.bytestreams.BytestreamSession; /** - * Created by vanitas on 27.07.17. + * Callback used to signal success/failure of the transport component. */ public interface JingleTransportCallback { + /** + * The {@link org.jivesoftware.smackx.jingle.component.JingleTransport} is ready to transfer data. + * @param bytestreamSession bytestreamSession which was established. + */ void onTransportReady(BytestreamSession bytestreamSession); + /** + * The {@link org.jivesoftware.smackx.jingle.component.JingleTransport} failed to establish a session. + * @param e exception. + */ void onTransportFailed(Exception e); } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/callbacks/package-info.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/callback/package-info.java similarity index 93% rename from smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/callbacks/package-info.java rename to smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/callback/package-info.java index d51d7d3d2..0be88f3c9 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/callbacks/package-info.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/callback/package-info.java @@ -19,4 +19,4 @@ * Smack's API for XEP-0166: Jingle. * Callbacks. */ -package org.jivesoftware.smackx.jingle.callbacks; +package org.jivesoftware.smackx.jingle.callback; diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/component/JingleContent.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/component/JingleContent.java index 0a6fa65b5..66bfdc4a9 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/component/JingleContent.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/component/JingleContent.java @@ -35,8 +35,8 @@ import org.jivesoftware.smackx.jingle.JingleTransportManager; import org.jivesoftware.smackx.jingle.adapter.JingleDescriptionAdapter; import org.jivesoftware.smackx.jingle.adapter.JingleSecurityAdapter; import org.jivesoftware.smackx.jingle.adapter.JingleTransportAdapter; -import org.jivesoftware.smackx.jingle.callbacks.JingleSecurityCallback; -import org.jivesoftware.smackx.jingle.callbacks.JingleTransportCallback; +import org.jivesoftware.smackx.jingle.callback.JingleSecurityCallback; +import org.jivesoftware.smackx.jingle.callback.JingleTransportCallback; import org.jivesoftware.smackx.jingle.element.JingleContentDescriptionElement; import org.jivesoftware.smackx.jingle.element.JingleContentElement; import org.jivesoftware.smackx.jingle.element.JingleContentSecurityElement; @@ -64,10 +64,25 @@ public class JingleContent implements JingleTransportCallback, JingleSecurityCal private final Set transportBlacklist = Collections.synchronizedSet(new HashSet()); + /** + * Create an empty JingleContent with random name. + * @param creator creator. + * @param senders sender. + */ public JingleContent(JingleContentElement.Creator creator, JingleContentElement.Senders senders) { this(null, null, null, randomName(), null, creator, senders); } + /** + * Create a JingleContent. + * @param description description component. + * @param transport transport component. + * @param security security component. + * @param name content name. + * @param disposition disposition. + * @param creator creator. + * @param senders senders. + */ public JingleContent(JingleDescription description, JingleTransport transport, JingleSecurity security, String name, String disposition, JingleContentElement.Creator creator, JingleContentElement.Senders senders) { setDescription(description); setTransport(transport); @@ -78,6 +93,11 @@ public class JingleContent implements JingleTransportCallback, JingleSecurityCal this.senders = senders; } + /** + * Create a new JingleContent from a {@link JingleContentElement}. + * @param content contentElement. + * @return jingleContent. + */ public static JingleContent fromElement(JingleContentElement content) { JingleDescription description = null; JingleTransport transport = null; @@ -116,12 +136,23 @@ public class JingleContent implements JingleTransportCallback, JingleSecurityCal return new JingleContent(description, transport, security, content.getName(), content.getDisposition(), content.getCreator(), content.getSenders()); } + /** + * Set the senders attribute. + * @param senders new value. + */ public void setSenders(JingleContentElement.Senders senders) { this.senders = senders; } /* HANDLE_XYZ */ + /** + * Handle an incoming jingle request. This method basically routes incoming requests to different methods based on + * the value of the request's action attribute. + * @param request request. + * @param connection connection. + * @return result. + */ public IQ handleJingleRequest(JingleElement request, XMPPConnection connection) { switch (request.getAction()) { case content_modify: @@ -145,11 +176,21 @@ public class JingleContent implements JingleTransportCallback, JingleSecurityCal } } + /** + * Handle incoming content-accept. + * @param request request. + * @param connection connection. + */ void handleContentAccept(JingleElement request, XMPPConnection connection) { start(connection); } - + /** + * Handle incoming session-accept. This means activating the transport and starting the transmission. + * @param request request. + * @param connection connection. + * @return result. + */ IQ handleSessionAccept(JingleElement request, XMPPConnection connection) { LOGGER.log(Level.INFO, "RECEIVED SESSION ACCEPT!"); JingleContentElement contentElement = null; @@ -169,26 +210,68 @@ public class JingleContent implements JingleTransportCallback, JingleSecurityCal return IQ.createResultIQ(request); } + /** + * Handle a content-modify request. + * TODO: Implement. + * @param request request. + * @param connection connection. + * @return result. + */ private IQ handleContentModify(JingleElement request, XMPPConnection connection) { return IQ.createErrorResponse(request, XMPPError.Condition.feature_not_implemented); } + /** + * Handle a description-info request. + * TODO: Implement. + * @param request request. + * @param connection connection. + * @return result. + */ private IQ handleDescriptionInfo(JingleElement request, XMPPConnection connection) { return IQ.createErrorResponse(request, XMPPError.Condition.feature_not_implemented); + //return description.handleDescriptionInfo(request.getContents().get(0).getDescription().getDescriptionInfo()); } + /** + * Handle a content-remove request. + * TODO: Implement. + * @param session session that has this content as child. + * @param connection connection. + */ public void handleContentRemove(JingleSession session, XMPPConnection connection) { } + /** + * Handle security-info requests. + * TODO: Implement. + * @param request request. + * @param connection connection. + * @return result. + */ private IQ handleSecurityInfo(JingleElement request, XMPPConnection connection) { return IQ.createErrorResponse(request, XMPPError.Condition.feature_not_implemented); } + /** + * Handle session-info requests. + * TODO: Implement. + * @param request request. + * @param connection connection. + * @return result. + */ private IQ handleSessionInfo(JingleElement request, XMPPConnection connection) { return IQ.createResultIQ(request); } + /** + * Handle transport-accept requests. + * This includes starting the transport and afterwards starting transmission. + * @param request request. + * @param connection connection. + * @return result. + */ private IQ handleTransportAccept(JingleElement request, XMPPConnection connection) { if (pendingReplacingTransport == null) { @@ -204,6 +287,13 @@ public class JingleContent implements JingleTransportCallback, JingleSecurityCal return IQ.createResultIQ(request); } + /** + * Handle transport-info requests. + * Pass the request down to the transport. + * @param request request. + * @param connection connection. + * @return result. + */ private IQ handleTransportInfo(JingleElement request, XMPPConnection connection) { assert request.getContents().size() == 1; JingleContentElement content = request.getContents().get(0); @@ -211,8 +301,16 @@ public class JingleContent implements JingleTransportCallback, JingleSecurityCal return transport.handleTransportInfo(content.getTransport().getInfo(), request); } + /** + * Handle a transport-reject request. + * That includes replacing the transport with the next choice. + * @param request request. + * @param connection connection. + * @return result. + */ private IQ handleTransportReject(JingleElement request, final XMPPConnection connection) { if (pendingReplacingTransport == null) { + // TODO: Throw other exception? throw new AssertionError("We didn't try to replace the transport."); } Async.go(new Runnable() { @@ -230,6 +328,14 @@ public class JingleContent implements JingleTransportCallback, JingleSecurityCal return IQ.createResultIQ(request); } + /** + * Handle a transport-replace request. + * That includes replacing the transport if suitable and starting the transmission. + * Otherwise reject the transport. + * @param request request. + * @param connection connection. + * @return result. + */ private IQ handleTransportReplace(final JingleElement request, final XMPPConnection connection) { //Tie Break? if (pendingReplacingTransport != null) { @@ -299,6 +405,10 @@ public class JingleContent implements JingleTransportCallback, JingleSecurityCal /* MISCELLANEOUS */ + /** + * Return a {@link JingleContentElement} representing this {@link JingleContent}. + * @return contentElement. + */ public JingleContentElement getElement() { JingleContentElement.Builder builder = JingleContentElement.getBuilder() .setName(name) @@ -321,36 +431,70 @@ public class JingleContent implements JingleTransportCallback, JingleSecurityCal return builder.build(); } + /** + * Return the transportBlacklist of this content. + * The blacklist contains the namespaces of {@link JingleTransport} classes, that this content will not offer/accept. + * @return transport blacklist. + */ public Set getTransportBlacklist() { return transportBlacklist; } + /** + * Get the creator of the content. The creator is the party that added the content to the session. + * @return creator. + */ public JingleContentElement.Creator getCreator() { return creator; } + /** + * Get the name of the content. + * @return content-name. + */ public String getName() { return name; } + /** + * Get the senders of the content. + * @return senders. + */ public JingleContentElement.Senders getSenders() { return senders; } + /** + * Set the parent {@link JingleSession} of the content. + * @param session session that has this content as child. + */ public void setParent(JingleSession session) { if (this.parent != session) { this.parent = session; } } + /** + * Return the parent {@link JingleSession} of this content. + * @return parent session. + */ public JingleSession getParent() { return parent; } + /** + * Return the {@link JingleDescription} of this content. + * @return jingle description component. + */ public JingleDescription getDescription() { return description; } + /** + * Set the {@link JingleDescription} of this content. + * If needed, set the parent of the description to this content. + * @param description jingle description component. + */ public void setDescription(JingleDescription description) { if (description != null && this.description != description) { this.description = description; @@ -358,10 +502,19 @@ public class JingleContent implements JingleTransportCallback, JingleSecurityCal } } + /** + * Return the {@link JingleTransport} of this content. + * @return jingle transport component. + */ public JingleTransport getTransport() { return transport; } + /** + * Set the {@link JingleTransport} of this content. + * If needed, set the parent of the transport component to this content. + * @param transport jingle transport component. + */ public void setTransport(JingleTransport transport) { if (transport != null && this.transport != transport) { this.transport = transport; @@ -369,10 +522,19 @@ public class JingleContent implements JingleTransportCallback, JingleSecurityCal } } + /** + * Return the {@link JingleSecurity} of this content. + * @return jingle security component. + */ public JingleSecurity getSecurity() { return security; } + /** + * Set the {@link JingleSecurity} of this content. + * If needed, set the parent of the security component to this content. + * @param security jingle security component. + */ public void setSecurity(JingleSecurity security) { if (security != null && this.security != security) { this.security = security; @@ -380,18 +542,30 @@ public class JingleContent implements JingleTransportCallback, JingleSecurityCal } } + /** + * Return true, if we are the sending party. Otherwise return false. + * @return true if we are sending. + */ public boolean isSending() { return (getSenders() == JingleContentElement.Senders.initiator && getParent().isInitiator()) || (getSenders() == JingleContentElement.Senders.responder && getParent().isResponder()) || getSenders() == JingleContentElement.Senders.both; } + /** + * Return true if we are the receiving party. Otherwise return false. + * @return true if we are receiving. + */ public boolean isReceiving() { return (getSenders() == JingleContentElement.Senders.initiator && getParent().isResponder()) || (getSenders() == JingleContentElement.Senders.responder && getParent().isInitiator()) || getSenders() == JingleContentElement.Senders.both; } + /** + * Prepare the security component (if any) and establish a bytestream session. + * @param connection connection + */ public void start(final XMPPConnection connection) { transport.prepare(connection); @@ -466,24 +640,48 @@ public class JingleContent implements JingleTransportCallback, JingleSecurityCal LOGGER.log(Level.SEVERE, "Security failed: " + e, e); } + /** + * Content finished locally. + */ public void onContentFinished() { JingleSession session = getParent(); session.onContentFinished(this); } + /** + * Content failed locally. + * @param e exception. + */ public void onContentFailed(Exception e) { } + /** + * Content cancelled locally. + */ public void onContentCancel() { JingleSession session = getParent(); session.onContentCancel(this); } + /** + * Handle incoming content-terminate. + * Pass it down to the description. + * @param reason reason. + */ public void handleContentTerminate(JingleReasonElement.Reason reason) { description.handleContentTerminate(reason); } + /** + * Locally replace the transport method. + * @param blacklist ignore all methods on the blacklist. + * @param connection connection. + * @throws SmackException.NotConnectedException + * @throws InterruptedException + * @throws XMPPException.XMPPErrorException + * @throws SmackException.NoResponseException + */ private void replaceTransport(Set blacklist, XMPPConnection connection) throws SmackException.NotConnectedException, InterruptedException, XMPPException.XMPPErrorException, SmackException.NoResponseException { @@ -510,6 +708,10 @@ public class JingleContent implements JingleTransportCallback, JingleSecurityCal connection.createStanzaCollectorAndSend(transportReplace).nextResultOrThrow(); } + /** + * Return a random content name. + * @return random name. + */ private static String randomName() { return "cont-" + StringUtils.randomString(16); } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/component/JingleDescription.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/component/JingleDescription.java index 3255712c6..46a57cad1 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/component/JingleDescription.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/component/JingleDescription.java @@ -27,25 +27,57 @@ import org.jivesoftware.smackx.jingle.element.JingleReasonElement; */ public abstract class JingleDescription { + /** + * Parent {@link JingleContent}. + */ private JingleContent parent; + /** + * Return a {@link JingleContentDescriptionElement} that represents this. + * @return element. + */ public abstract D getElement(); + /** + * Set the parent {@link JingleContent}. + * @param parent content. + */ public void setParent(JingleContent parent) { if (this.parent != parent) { this.parent = parent; } } + /** + * Handle a descriptionInfo. + * @param info info. + * @return result. + */ public abstract JingleElement handleDescriptionInfo(JingleContentDescriptionInfoElement info); + /** + * Return the parent {@link JingleContent} of this description. + * @return parent. + */ public JingleContent getParent() { return parent; } + /** + * Do work once the bytestreams are ready. + * @param bytestreamSession established bytestream session. + */ public abstract void onBytestreamReady(BytestreamSession bytestreamSession); + /** + * Return the namespace of the description. + * @return namespace. + */ public abstract String getNamespace(); + /** + * Handle an incoming session-terminate. + * @param reason reason of termination. + */ public abstract void handleContentTerminate(JingleReasonElement.Reason reason); } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/component/JingleSecurity.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/component/JingleSecurity.java index 762e4d271..af00bc160 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/component/JingleSecurity.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/component/JingleSecurity.java @@ -18,7 +18,7 @@ package org.jivesoftware.smackx.jingle.component; import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smackx.bytestreams.BytestreamSession; -import org.jivesoftware.smackx.jingle.callbacks.JingleSecurityCallback; +import org.jivesoftware.smackx.jingle.callback.JingleSecurityCallback; import org.jivesoftware.smackx.jingle.element.JingleContentSecurityElement; import org.jivesoftware.smackx.jingle.element.JingleContentSecurityInfoElement; import org.jivesoftware.smackx.jingle.element.JingleElement; @@ -30,27 +30,71 @@ import org.jxmpp.jid.FullJid; */ public abstract class JingleSecurity { + /** + * Parent of this security component. + */ private JingleContent parent; + /** + * Return a {@link JingleContentSecurityElement} that represents this {@link JingleSecurity} component. + * @return element. + */ public abstract D getElement(); + /** + * Handle an incoming security-info. + * @param element security info. + * @param wrapping jingleElement that contains the security info. + * @return result. + */ public abstract JingleElement handleSecurityInfo(JingleContentSecurityInfoElement element, JingleElement wrapping); + /** + * Set the parent {@link JingleContent} of this security component. + * @param parent parent. + */ public void setParent(JingleContent parent) { if (this.parent != parent) { this.parent = parent; } } + /** + * Return the parent {@link JingleContent} of this security component. + * @return parent. + */ public JingleContent getParent() { return parent; } + /** + * Decrypt an incoming bytestream. + * This includes wrapping the incoming {@link BytestreamSession} in a {@link JingleSecurityBytestreamSession} and + * pass it to the callbacks {@link JingleSecurityCallback#onSecurityReady(BytestreamSession)} method. + * @param bytestreamSession encrypted bytestreamSession. + * @param callback callback. + */ public abstract void decryptIncomingBytestream(BytestreamSession bytestreamSession, JingleSecurityCallback callback); - public abstract void encryptOutgoingBytestream(BytestreamSession bytestreamSession, JingleSecurityCallback callbacks); + /** + * Encrypt an incoming bytestream. + * This includes wrapping the incoming {@link BytestreamSession} in a {@link JingleSecurityBytestreamSession} and + * pass it to the callbacks {@link JingleSecurityCallback#onSecurityReady(BytestreamSession)} method. + * @param bytestreamSession encrypted bytestreamSession. + * @param callback callback. + */ + public abstract void encryptOutgoingBytestream(BytestreamSession bytestreamSession, JingleSecurityCallback callback); + /** + * Return the namespace of this security component. + * @return namespace. + */ public abstract String getNamespace(); - public abstract void prepare(XMPPConnection connection, FullJid sender); + /** + * Prepare the security session. + * @param connection connection. + * @param peer peer. + */ + public abstract void prepare(XMPPConnection connection, FullJid peer); } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/component/JingleSecurityBytestreamSession.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/component/JingleSecurityBytestreamSession.java index 0988dd07b..8416a3435 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/component/JingleSecurityBytestreamSession.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/component/JingleSecurityBytestreamSession.java @@ -21,12 +21,23 @@ import java.io.IOException; import org.jivesoftware.smackx.bytestreams.BytestreamSession; /** - * Created by vanitas on 27.07.17. + * Wrapper class that wraps a {@link BytestreamSession} to add a layer of security. */ public abstract class JingleSecurityBytestreamSession implements BytestreamSession { + /** + * Wrapped {@link BytestreamSession}. + */ protected BytestreamSession wrapped; + /** + * Constructor. + * @param session {@link BytestreamSession} that will be wrapped. + */ + public JingleSecurityBytestreamSession(BytestreamSession session) { + this.wrapped = session; + } + @Override public int getReadTimeout() throws IOException { return wrapped.getReadTimeout(); @@ -36,8 +47,4 @@ public abstract class JingleSecurityBytestreamSession implements BytestreamSessi public void setReadTimeout(int timeout) throws IOException { wrapped.setReadTimeout(timeout); } - - public JingleSecurityBytestreamSession(BytestreamSession session) { - this.wrapped = session; - } } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/component/JingleSession.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/component/JingleSession.java index b3da1f4d7..96c35dd40 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/component/JingleSession.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/component/JingleSession.java @@ -48,11 +48,29 @@ import org.jxmpp.jid.FullJid; public class JingleSession { private static final Logger LOGGER = Logger.getLogger(JingleSession.class.getName()); + /** + * Map of contents in this session. + */ private final ConcurrentHashMap contents = new ConcurrentHashMap<>(); + + /** + * Map of proposed (added, but not yet accepted contents) in this session. + */ private final ConcurrentHashMap proposedContents = new ConcurrentHashMap<>(); + + /** + * Reference to jingleManager. + */ private final JingleManager jingleManager; + /** + * Initiator and responder of the session. + */ private final FullJid initiator, responder; + + /** + * Our role in the session (initiator or responder). + */ private final Role role; private final String sessionId; @@ -63,8 +81,19 @@ public class JingleSession { ended //post-session-terminate } + /** + * Current state of the session. + */ private SessionState sessionState; + /** + * Create a new JingleSession. + * @param manager jingleManager. + * @param initiator initiator of the session. + * @param responder responder of the session. + * @param role our role in the session. + * @param sessionId session id. + */ public JingleSession(JingleManager manager, FullJid initiator, FullJid responder, Role role, String sessionId) { this.jingleManager = manager; this.initiator = initiator; @@ -74,6 +103,16 @@ public class JingleSession { this.sessionState = SessionState.fresh; } + /** + * Parse a {@link JingleSession} from a {@link JingleElement} with action session-initiate. + * @param manager jingleManager. + * @param initiate {@link JingleElement} with session-initiate action. + * @return jingleSession. + * TODO: Throw exceptions. + * @throws UnsupportedSecurityException + * @throws UnsupportedDescriptionException + * @throws UnsupportedTransportException + */ public static JingleSession fromSessionInitiate(JingleManager manager, JingleElement initiate) throws UnsupportedSecurityException, UnsupportedDescriptionException, UnsupportedTransportException { if (initiate.getAction() != JingleAction.session_initiate) { @@ -92,21 +131,47 @@ public class JingleSession { return session; } + /** + * Send a session-initiate request to the responder. + * This sets the state from fresh to pending. + * @param connection connection. + * @throws SmackException.NotConnectedException + * @throws InterruptedException + * @throws XMPPException.XMPPErrorException + * @throws SmackException.NoResponseException + */ public void sendInitiate(XMPPConnection connection) throws SmackException.NotConnectedException, InterruptedException, XMPPException.XMPPErrorException, SmackException.NoResponseException { if (this.sessionState != SessionState.fresh) { throw new IllegalStateException("Session is not in fresh state."); } + if (!isInitiator()) { + throw new IllegalStateException("We are not the initiator."); + } + connection.createStanzaCollectorAndSend(createSessionInitiate()).nextResultOrThrow(); this.sessionState = SessionState.pending; } + /** + * Send a session-accept to the initiator. + * This sets the state from pending to active. + * @param connection connection. + * @throws SmackException.NotConnectedException + * @throws InterruptedException + * @throws XMPPException.XMPPErrorException + * @throws SmackException.NoResponseException + */ public void sendAccept(XMPPConnection connection) throws SmackException.NotConnectedException, InterruptedException, XMPPException.XMPPErrorException, SmackException.NoResponseException { LOGGER.log(Level.INFO, "Accepted session."); if (this.sessionState != SessionState.pending) { throw new IllegalStateException("Session is not in pending state."); } + if (!isResponder()) { + throw new IllegalStateException("We are not the responder."); + } + if (contents.values().size() == 0) { LOGGER.log(Level.WARNING, "0 contents!"); } @@ -119,6 +184,10 @@ public class JingleSession { this.sessionState = SessionState.active; } + /** + * Create a session-initiate request. + * @return request. + */ public JingleElement createSessionInitiate() { if (role != Role.initiator) { throw new IllegalStateException("Sessions role is not initiator."); @@ -132,6 +201,10 @@ public class JingleSession { return JingleElement.createSessionInitiate(getInitiator(), getResponder(), getSessionId(), contentElements); } + /** + * Create a session-accept request. + * @return request. + */ public JingleElement createSessionAccept() { if (role != Role.responder) { throw new IllegalStateException("Sessions role is not responder."); @@ -207,9 +280,16 @@ public class JingleSession { } catch (SmackException.NotConnectedException | InterruptedException e) { LOGGER.log(Level.SEVERE, "Could not send session-terminate: " + e, e); } + this.sessionState = SessionState.ended; jingleManager.removeSession(this); } + /** + * Handle incoming jingle request. + * This is a routing function which routes the request to the suitable method based on the value of the action field. + * @param request incoming request. + * @return result. + */ public IQ handleJingleRequest(JingleElement request) { switch (request.getAction()) { case content_modify: @@ -243,8 +323,9 @@ public class JingleSession { /* ############## Processed in this class ############## */ /** - * Handle incoming session-accept stanza. - * @param request session-accept stanza. + * Handle incoming session-accept request. + * This passes the session-accept to all contents. + * @param request session-accept request. * @return result. */ private IQ handleSessionAccept(final JingleElement request) { @@ -262,13 +343,17 @@ public class JingleSession { return IQ.createResultIQ(request); } + /** + * Handle incoming session-initiate request. + * Notifies content listeners of respective descriptions about incoming requests. + * @param request request. + * @return result. + */ private IQ handleSessionInitiate(JingleElement request) { final JingleDescription description = getSoleContentOrThrow().getDescription(); final JingleDescriptionManager descriptionManager = jingleManager.getDescriptionManager(description.getNamespace()); + sessionState = SessionState.pending; - if (descriptionManager == null) { - - } Async.go(new Runnable() { @Override public void run() { @@ -290,6 +375,13 @@ public class JingleSession { return IQ.createResultIQ(request); } + /** + * Handle incoming session-terminate request. + * This includes passing down the request to child contents, setting the sessionState to ended and removing the session + * from the {@link JingleManager}. + * @param request request. + * @return result. + */ private IQ handleSessionTerminate(JingleElement request) { this.sessionState = SessionState.ended; JingleReasonElement reason = request.getReason(); @@ -304,17 +396,25 @@ public class JingleSession { content.handleContentTerminate(r); } + sessionState = SessionState.ended; jingleManager.removeSession(this); return IQ.createResultIQ(request); } + /** + * Handle incoming content-accept request. + * This includes moving affected contents from proposedContents to contents and notifying them. + * @param request request. + * @return result. + */ private IQ handleContentAccept(final JingleElement request) { for (JingleContentElement a : request.getContents()) { final JingleContent accepted = proposedContents.get(a.getName()); if (accepted == null) { throw new AssertionError("Illegal content name!"); + //TODO: Throw other exception? } proposedContents.remove(accepted.getName()); @@ -331,6 +431,12 @@ public class JingleSession { return IQ.createResultIQ(request); } + /** + * Handle a content-add request. + * This includes notifying respective {@link JingleDescriptionManager} about the request. + * @param request request. + * @return result. + */ private IQ handleContentAdd(JingleElement request) { final JingleContent proposed = getSoleProposedContentOrThrow(request); @@ -350,6 +456,12 @@ public class JingleSession { return IQ.createResultIQ(request); } + /** + * Handle incoming content-reject requests. + * That includes removing the affected contents from the proposedContents map. + * @param request request. + * @return result. + */ private IQ handleContentReject(JingleElement request) { for (JingleContentElement r : request.getContents()) { final JingleContent rejected = proposedContents.get(r.getName()); @@ -373,6 +485,12 @@ public class JingleSession { return IQ.createResultIQ(request); } + /** + * Handle incoming content-remove requests. + * TODO: Implement. + * @param request request. + * @return result. + */ private IQ handleContentRemove(final JingleElement request) { return IQ.createErrorResponse(request, XMPPError.Condition.feature_not_implemented); /* @@ -397,34 +515,66 @@ public class JingleSession { */ } + /** + * Return the {@link FullJid} of the initiator. + * @return initiators {@link FullJid} + */ public FullJid getInitiator() { return initiator; } + /** + * Return the {@link FullJid} of the responder. + * @return responders {@link FullJid} + */ public FullJid getResponder() { return responder; } + /** + * Return the {@link FullJid} of the peer (the other party of the session). + * @return peers {@link FullJid} + */ public FullJid getPeer() { return role == Role.initiator ? responder : initiator; } + /** + * Return our {@link FullJid}. + * @return our {@link FullJid}. + */ public FullJid getOurJid() { return role == Role.initiator ? initiator : responder; } + /** + * Return true, if we are the initiator. + * @return initiator? + */ public boolean isInitiator() { return role == Role.initiator; } + /** + * Return true, if we are the responder. + * @return responder? + */ public boolean isResponder() { return role == Role.responder; } + /** + * Return the SID of this session. + * @return sessionId. + */ public String getSessionId() { return sessionId; } + /** + * Return the {@link JingleManager} of this session. + * @return jingleManager. + */ public JingleManager getJingleManager() { return jingleManager; } @@ -441,6 +591,15 @@ public class JingleSession { return map; } + /** + * If the request contains only one {@link JingleContentElement} and this session contains the + * related {@link JingleContent}, return that {@link JingleContent}. + * If the request contains more than one {@link JingleContentElement}, throw an AssertionError. + * If the session does not contain the {@link JingleContent} related to the {@link JingleContentElement} from the + * request, throw an AssertionError. + * @param request request. + * @return the only affected content, or throw. + */ private JingleContent getSoleAffectedContentOrThrow(JingleElement request) { if (request.getContents().size() != 1) { throw new AssertionError("More/less than 1 content in request!"); @@ -454,6 +613,12 @@ public class JingleSession { return content; } + /** + * If the request cotains only one {@link JingleContentElement}, parse it in a {@link JingleContent} and return it. + * Otherwise throw an AssertionError. + * @param request request. + * @return sole proposed content or throw. + */ private static JingleContent getSoleProposedContentOrThrow(JingleElement request) { if (request.getContents().size() != 1) { throw new AssertionError("More/less than 1 content in request!"); @@ -462,6 +627,11 @@ public class JingleSession { return JingleContent.fromElement(request.getContents().get(0)); } + /** + * Add a {@link JingleContent} to the session. + * @throws IllegalArgumentException if the session already contains the content. + * @param content content. + */ public void addContent(JingleContent content) { if (contents.get(content.getName()) != null) { throw new IllegalArgumentException("Session already contains a content with the name " + content.getName()); @@ -470,15 +640,32 @@ public class JingleSession { content.setParent(this); } + /** + * Add a {@link JingleContent}, which gets parsed from the given {@link JingleContentElement} to the session. + * @param content contentElement. + * @param manager JingleManager. + * @throws UnsupportedSecurityException + * @throws UnsupportedTransportException + * @throws UnsupportedDescriptionException + */ public void addContent(JingleContentElement content, JingleManager manager) throws UnsupportedSecurityException, UnsupportedTransportException, UnsupportedDescriptionException { addContent(JingleContent.fromElement(content)); } + /** + * Return the map of {@link JingleContent}s of this session. + * @return contents. + */ public ConcurrentHashMap getContents() { return contents; } + /** + * Return the {@link JingleContent} with the given name, or null if the session does not contain that content. + * @param name name. + * @return content or null. + */ public JingleContent getContent(String name) { return contents.get(name); } @@ -502,6 +689,10 @@ public class JingleSession { return contents.values().iterator().next(); } + /** + * Return the state of the session. + * @return state. + */ public SessionState getSessionState() { return sessionState; } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/component/JingleTransport.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/component/JingleTransport.java index 914327581..4b310be48 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/component/JingleTransport.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/component/JingleTransport.java @@ -23,7 +23,7 @@ import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.packet.IQ; import org.jivesoftware.smackx.bytestreams.BytestreamSession; -import org.jivesoftware.smackx.jingle.callbacks.JingleTransportCallback; +import org.jivesoftware.smackx.jingle.callback.JingleTransportCallback; import org.jivesoftware.smackx.jingle.element.JingleContentTransportElement; import org.jivesoftware.smackx.jingle.element.JingleContentTransportInfoElement; import org.jivesoftware.smackx.jingle.element.JingleElement; @@ -34,15 +34,35 @@ import org.jivesoftware.smackx.jingle.element.JingleElement; public abstract class JingleTransport { private JingleContent parent; + + /** + * List of transport candidates that we proposed to the peer. + */ private final ArrayList> ourCandidates = new ArrayList<>(); + + /** + * List of transport candidates that our peer proposed to us. + */ private final ArrayList> theirCandidates = new ArrayList<>(); + /** + * The {@link BytestreamSession} we try to establish. + */ protected BytestreamSession bytestreamSession; + /** + * Return a {@link JingleContentTransportElement} which represents the state of this. + * @return element. + */ public abstract D getElement(); + /** + * Add a {@link JingleTransportCandidate} to the list of our proposed candidates. + * The insertion is made sorted with descending priority. + * @param candidate candidate. + */ public void addOurCandidate(JingleTransportCandidate candidate) { -// Insert sorted by descending priority + // Insert sorted by descending priority int i; // Find appropriate index for (i = 0; i < ourCandidates.size(); i++) { @@ -62,6 +82,11 @@ public abstract class JingleTransport { candidate.setParent(this); } + /** + * Add a {@link JingleTransportCandidate} to the list of their proposed candidates. + * The insertion is made sorted with descending priority. + * @param candidate candidate. + */ public void addTheirCandidate(JingleTransportCandidate candidate) { // Insert sorted by descending priority int i; @@ -83,35 +108,93 @@ public abstract class JingleTransport { candidate.setParent(this); } + /** + * Prepare the transport (can be used to register listeners etc.). + * @param connection connection. + */ public abstract void prepare(XMPPConnection connection); + /** + * Return the list of {@link JingleTransportCandidate}s we proposed. + * @return our candidates + */ public List> getOurCandidates() { return ourCandidates; } + /** + * Return the list of {@link JingleTransportCandidate}s our peer proposed to us. + * @return their candidates. + */ public List> getTheirCandidates() { return theirCandidates; } + /** + * Return the namespace of this transport. + * @return namespace. + */ public abstract String getNamespace(); + /** + * Establish a incoming {@link BytestreamSession} with peer. + * On success, call {@link JingleTransportCallback#onTransportReady(BytestreamSession)}. + * On failure, call {@link JingleTransportCallback#onTransportFailed(Exception)}. + * @param connection connection + * @param callback callback + * @param session {@link JingleSession} in which's context we try to connect. + * @throws SmackException.NotConnectedException + * @throws InterruptedException + */ public abstract void establishIncomingBytestreamSession(XMPPConnection connection, JingleTransportCallback callback, JingleSession session) throws SmackException.NotConnectedException, InterruptedException; + /** + * Establish a outgoing {@link BytestreamSession} with peer. + * On success, call {@link JingleTransportCallback#onTransportReady(BytestreamSession)}. + * On failure, call {@link JingleTransportCallback#onTransportFailed(Exception)}. + * @param connection connection + * @param callback callback + * @param session {@link JingleSession} in which's context we try to connect. + * @throws SmackException.NotConnectedException + * @throws InterruptedException + */ public abstract void establishOutgoingBytestreamSession(XMPPConnection connection, JingleTransportCallback callback, JingleSession session) throws SmackException.NotConnectedException, InterruptedException; + /** + * Handle an incoming transport-info request. + * @param info info + * @param wrapping wrapping {@link JingleElement}. + * @return result. + */ public abstract IQ handleTransportInfo(JingleContentTransportInfoElement info, JingleElement wrapping); + /** + * Set the parent {@link JingleContent} of this transport component. + * @param parent content. + */ public void setParent(JingleContent parent) { this.parent = parent; } + /** + * Return the parent {@link JingleContent} of this transport component. + * @return content. + */ public JingleContent getParent() { return parent; } + /** + * Handle an incoming session-accept request. + * @param transportElement the {@link JingleContentTransportElement} we received + * @param connection connection. + */ public abstract void handleSessionAccept(JingleContentTransportElement transportElement, XMPPConnection connection); + /** + * Shut down components etc. + */ public abstract void cleanup(); } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/component/JingleTransportCandidate.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/component/JingleTransportCandidate.java index 7a6af1b29..b5f092edb 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/component/JingleTransportCandidate.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/component/JingleTransportCandidate.java @@ -23,26 +23,53 @@ import org.jivesoftware.smackx.jingle.element.JingleContentTransportCandidateEle */ public abstract class JingleTransportCandidate { + /** + * Parent {@link JingleTransport}, which contains this as a child candidate. + */ private JingleTransport parent; + + /** + * Priority of this candidate. + */ private int priority; + /** + * Set the parent {@link JingleTransport}. + * @param transport parent. + */ public void setParent(JingleTransport transport) { if (parent != transport) { parent = transport; } } + /** + * Return the parent {@link JingleTransport}. + * @return parent transport. + */ public JingleTransport getParent() { return parent; } + /** + * Return the priority of this candidate. + * @return priority. + */ public int getPriority() { return priority; } + /** + * Set the priority of this candidate. + * @param priority priority. + */ public void setPriority(int priority) { this.priority = priority; } + /** + * Return an {@link JingleContentTransportCandidateElement} which represents this. + * @return element. + */ public abstract E getElement(); } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_ibb/JingleIBBTransport.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_ibb/JingleIBBTransport.java index 9403f75ec..086effee9 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_ibb/JingleIBBTransport.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_ibb/JingleIBBTransport.java @@ -28,7 +28,7 @@ import org.jivesoftware.smackx.bytestreams.BytestreamSession; import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamListener; import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager; import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamRequest; -import org.jivesoftware.smackx.jingle.callbacks.JingleTransportCallback; +import org.jivesoftware.smackx.jingle.callback.JingleTransportCallback; import org.jivesoftware.smackx.jingle.component.JingleSession; import org.jivesoftware.smackx.jingle.component.JingleTransport; import org.jivesoftware.smackx.jingle.component.JingleTransportCandidate; 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 e3b7e676b..fe000bafc 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 @@ -33,7 +33,7 @@ import org.jivesoftware.smackx.bytestreams.socks5.Socks5Proxy; 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.callbacks.JingleTransportCallback; +import org.jivesoftware.smackx.jingle.callback.JingleTransportCallback; import org.jivesoftware.smackx.jingle.component.JingleSession; import org.jivesoftware.smackx.jingle.component.JingleTransport; import org.jivesoftware.smackx.jingle.component.JingleTransportCandidate; diff --git a/smack-integration-test/src/main/java/org/jivesoftware/smackx/jingle/transport/JingleTransportIntegrationTest.java b/smack-integration-test/src/main/java/org/jivesoftware/smackx/jingle/transport/JingleTransportIntegrationTest.java index c34ab0227..7a706545a 100644 --- a/smack-integration-test/src/main/java/org/jivesoftware/smackx/jingle/transport/JingleTransportIntegrationTest.java +++ b/smack-integration-test/src/main/java/org/jivesoftware/smackx/jingle/transport/JingleTransportIntegrationTest.java @@ -29,7 +29,7 @@ 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.callback.JingleTransportCallback; import org.jivesoftware.smackx.jingle.component.JingleContent; import org.jivesoftware.smackx.jingle.component.JingleSession; import org.jivesoftware.smackx.jingle.component.JingleTransport;