From d7f974dc69fdecc67920861dc675f2039dcd97af Mon Sep 17 00:00:00 2001 From: vanitasvitae Date: Thu, 17 Aug 2017 12:18:33 +0200 Subject: [PATCH] Add support for XEP-0166, XEP-0260, XEP-0261 --- .../jivesoftware/smack/util/ParserUtils.java | 57 +- .../smack/util/XmlStringBuilder.java | 12 + .../JingleFileTransferManager.java | 43 -- .../jingle_filetransfer/element/Checksum.java | 63 -- .../element/JingleFileTransferChild.java | 167 ----- .../jingle_filetransfer/element/Range.java | 135 ----- .../provider/ChecksumProvider.java | 90 --- .../provider/JingleFileTransferProvider.java | 120 ---- .../bytestreams/socks5/Socks5Proxy.java | 2 +- .../bytestreams/socks5/packet/Bytestream.java | 22 + ....java => JingleDescriptionController.java} | 19 +- ...ler.java => JingleDescriptionManager.java} | 16 +- .../smackx/jingle/JingleManager.java | 291 ++++++--- .../smackx/jingle/JingleSecurityManager.java | 25 + .../smackx/jingle/JingleSession.java | 230 ------- .../smackx/jingle/JingleTransportManager.java | 42 ++ .../jingle/JingleTransportMethodManager.java | 132 ---- .../smackx/jingle/JingleUtil.java | 490 --------------- .../adapter/JingleDescriptionAdapter.java | 32 + .../jingle/adapter/JingleSecurityAdapter.java | 30 + .../adapter/JingleTransportAdapter.java | 30 + .../smackx/jingle/adapter/package-info.java | 22 + .../JingleSecurityCallback.java} | 11 +- .../callbacks/JingleTransportCallback.java | 29 + .../smackx/jingle/callbacks/package-info.java | 22 + .../jingle/component/JingleContent.java | 492 +++++++++++++++ .../jingle/component/JingleDescription.java | 48 ++ .../jingle/component/JingleSecurity.java | 56 ++ .../JingleSecurityBytestreamSession.java | 43 ++ .../jingle/component/JingleSession.java | 424 +++++++++++++ .../jingle/component/JingleTransport.java | 117 ++++ .../component/JingleTransportCandidate.java | 48 ++ .../jingle/component}/package-info.java | 8 +- .../smackx/jingle/element/Jingle.java | 235 -------- .../smackx/jingle/element/JingleAction.java | 4 +- .../JingleContentDescriptionChildElement.java | 9 + ...a => JingleContentDescriptionElement.java} | 15 +- ... JingleContentDescriptionInfoElement.java} | 4 +- ...Content.java => JingleContentElement.java} | 60 +- .../element/JingleContentSecurityElement.java | 52 ++ .../JingleContentSecurityInfoElement.java | 10 +- ...ngleContentTransportCandidateElement.java} | 11 +- ...ava => JingleContentTransportElement.java} | 22 +- .../JingleContentTransportInfoElement.java | 37 ++ .../smackx/jingle/element/JingleElement.java | 570 ++++++++++++++++++ ...ngleError.java => JingleErrorElement.java} | 14 +- ...leReason.java => JingleReasonElement.java} | 44 +- ...knownJingleContentDescriptionElement.java} | 6 +- .../UnknownJingleContentSecurityElement.java | 54 ++ ...UnknownJingleContentTransportElement.java} | 10 +- .../exception/FailedTransportException.java | 29 + .../UnsupportedDescriptionException.java | 23 +- .../UnsupportedSecurityException.java} | 16 +- .../UnsupportedTransportException.java | 35 ++ .../smackx/jingle/exception/package-info.java | 22 + .../smackx/jingle/package-info.java | 2 +- .../JingleContentDescriptionProvider.java | 6 +- .../JingleContentProviderManager.java | 45 -- .../JingleContentSecurityProvider.java | 35 ++ .../JingleContentTransportProvider.java | 6 +- .../jingle/provider/JingleErrorProvider.java | 9 +- .../jingle/provider/JingleProvider.java | 189 +++--- .../BytestreamSessionEstablishedListener.java | 30 + .../jingle_ibb/JingleIBBTransport.java | 150 +++++ .../jingle_ibb/JingleIBBTransportAdapter.java | 37 ++ .../jingle_ibb/JingleIBBTransportManager.java | 92 +++ .../element/JingleIBBTransportElement.java} | 50 +- .../jingle_ibb/element/package-info.java | 2 +- .../jingle_ibb}/package-info.java | 2 +- .../provider/JingleIBBTransportProvider.java | 25 +- .../jingle_ibb/provider/package-info.java | 2 +- .../jingle_s5b/JingleS5BTransport.java | 462 ++++++++++++++ .../jingle_s5b/JingleS5BTransportAdapter.java | 49 ++ .../JingleS5BTransportCandidate.java | 152 +++++ .../jingle_s5b/JingleS5BTransportManager.java | 308 ++++++++++ .../jingle_s5b/S5BTransportException.java | 47 ++ .../JingleS5BTransportCandidateElement.java} | 18 +- .../element/JingleS5BTransportElement.java} | 54 +- .../JingleS5BTransportInfoElement.java} | 32 +- .../jingle_s5b/element}/package-info.java | 2 +- .../jingle_s5b/package-info.java | 2 +- .../provider/JingleS5BTransportProvider.java | 72 ++- .../jingle_s5b/provider/package-info.java | 2 +- .../smackx/jingle/transport/package-info.java | 22 + .../transports/JingleTransportManager.java | 74 --- .../transports/JingleTransportSession.java | 62 -- .../jingle_ibb/JingleIBBTransportManager.java | 64 -- .../jingle_ibb/JingleIBBTransportSession.java | 115 ---- .../jingle_s5b/JingleS5BTransportManager.java | 234 ------- .../jingle_s5b/JingleS5BTransportSession.java | 361 ----------- .../{ => util}/FullJidAndSessionId.java | 2 +- .../smackx/jingle/{ => util}/Role.java | 2 +- .../smackx/jingle/util/package-info.java | 22 + .../jingle/FullJidAndSessionIdTest.java | 48 ++ .../jingle/JingleContentElementTest.java | 160 +++++ .../smackx/jingle/JingleContentTest.java | 76 --- .../smackx/jingle/JingleElementTest.java | 447 ++++++++++++++ ...rTest.java => JingleErrorElementTest.java} | 14 +- ...Test.java => JingleReasonElementTest.java} | 44 +- .../smackx/jingle/JingleTest.java | 81 --- .../smackx/jingle/JingleUtilTest.java | 102 ---- .../jingle/component/JingleContentTest.java | 43 ++ .../jingle/component/JingleSessionTest.java | 251 ++++++++ .../JingleContentProviderManagerTest.java | 26 +- .../jingle/provider/JingleProviderTest.java | 17 +- .../JingleTransportComparatorTest.java | 40 ++ .../jingle_ibb/JingleIBBTransportTest.java | 90 +++ .../jingle_s5b/JingleS5BTransportTest.java | 311 ++++++++++ .../jingle_ibb/JingleIBBTransportTest.java | 76 --- .../jingle_s5b/JingleS5BTransportTest.java | 226 ------- .../smackx/jingle}/package-info.java | 4 +- .../JingleTransportIntegrationTest.java | 191 ++++++ .../jingle/transport}/package-info.java | 4 +- 113 files changed, 6016 insertions(+), 3725 deletions(-) delete mode 100644 smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/JingleFileTransferManager.java delete mode 100644 smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/element/Checksum.java delete mode 100644 smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/element/JingleFileTransferChild.java delete mode 100644 smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/element/Range.java delete mode 100644 smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/provider/ChecksumProvider.java delete mode 100644 smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/provider/JingleFileTransferProvider.java rename smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/{JingleHandler.java => JingleDescriptionController.java} (56%) rename smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/{JingleSessionHandler.java => JingleDescriptionManager.java} (60%) create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleSecurityManager.java delete mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleSession.java create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleTransportManager.java delete mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleTransportMethodManager.java delete mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleUtil.java create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/adapter/JingleDescriptionAdapter.java create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/adapter/JingleSecurityAdapter.java create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/adapter/JingleTransportAdapter.java create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/adapter/package-info.java rename smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/{transports/JingleTransportInitiationCallback.java => callbacks/JingleSecurityCallback.java} (71%) create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/callbacks/JingleTransportCallback.java create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/callbacks/package-info.java create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/component/JingleContent.java create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/component/JingleDescription.java create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/component/JingleSecurity.java create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/component/JingleSecurityBytestreamSession.java create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/component/JingleSession.java create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/component/JingleTransport.java create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/component/JingleTransportCandidate.java rename {smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/element => smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/component}/package-info.java (72%) delete mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/Jingle.java rename smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/{JingleContentDescription.java => JingleContentDescriptionElement.java} (80%) rename smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/{JingleContentTransportInfo.java => JingleContentDescriptionInfoElement.java} (85%) rename smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/{JingleContent.java => JingleContentElement.java} (73%) create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentSecurityElement.java rename smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/provider/package-info.java => smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentSecurityInfoElement.java (73%) rename smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/{JingleContentTransportCandidate.java => JingleContentTransportCandidateElement.java} (75%) rename smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/{JingleContentTransport.java => JingleContentTransportElement.java} (71%) create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentTransportInfoElement.java create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleElement.java rename smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/{JingleError.java => JingleErrorElement.java} (79%) rename smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/{JingleReason.java => JingleReasonElement.java} (64%) rename smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/{UnknownJingleContentDescription.java => UnknownJingleContentDescriptionElement.java} (84%) create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/UnknownJingleContentSecurityElement.java rename smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/{UnknownJingleContentTransport.java => UnknownJingleContentTransportElement.java} (80%) create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/exception/FailedTransportException.java rename smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/element/JingleFileTransfer.java => smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/exception/UnsupportedDescriptionException.java (54%) rename smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/{transports/JingleTransportInitiationException.java => exception/UnsupportedSecurityException.java} (59%) create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/exception/UnsupportedTransportException.java create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/exception/package-info.java delete mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/provider/JingleContentProviderManager.java create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/provider/JingleContentSecurityProvider.java create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/BytestreamSessionEstablishedListener.java create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_ibb/JingleIBBTransport.java create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_ibb/JingleIBBTransportAdapter.java create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_ibb/JingleIBBTransportManager.java rename smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/{transports/jingle_ibb/element/JingleIBBTransport.java => transport/jingle_ibb/element/JingleIBBTransportElement.java} (61%) rename smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/{transports => transport}/jingle_ibb/element/package-info.java (91%) rename smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/{transports => transport/jingle_ibb}/package-info.java (92%) rename smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/{transports => transport}/jingle_ibb/provider/JingleIBBTransportProvider.java (55%) rename smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/{transports => transport}/jingle_ibb/provider/package-info.java (91%) create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/JingleS5BTransport.java create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/JingleS5BTransportAdapter.java create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/JingleS5BTransportCandidate.java create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/JingleS5BTransportManager.java create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/S5BTransportException.java rename smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/{transports/jingle_s5b/elements/JingleS5BTransportCandidate.java => transport/jingle_s5b/element/JingleS5BTransportCandidateElement.java} (88%) rename smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/{transports/jingle_s5b/elements/JingleS5BTransport.java => transport/jingle_s5b/element/JingleS5BTransportElement.java} (71%) rename smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/{transports/jingle_s5b/elements/JingleS5BTransportInfo.java => transport/jingle_s5b/element/JingleS5BTransportInfoElement.java} (85%) rename smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/{transports/jingle_s5b/elements => transport/jingle_s5b/element}/package-info.java (91%) rename smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/{transports => transport}/jingle_s5b/package-info.java (92%) rename smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/{transports => transport}/jingle_s5b/provider/JingleS5BTransportProvider.java (57%) rename smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/{transports => transport}/jingle_s5b/provider/package-info.java (91%) create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/package-info.java delete mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/JingleTransportManager.java delete mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/JingleTransportSession.java delete mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_ibb/JingleIBBTransportManager.java delete mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_ibb/JingleIBBTransportSession.java delete mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_s5b/JingleS5BTransportManager.java delete mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_s5b/JingleS5BTransportSession.java rename smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/{ => util}/FullJidAndSessionId.java (97%) rename smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/{ => util}/Role.java (93%) create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/util/package-info.java create mode 100644 smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/FullJidAndSessionIdTest.java create mode 100644 smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/JingleContentElementTest.java delete mode 100644 smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/JingleContentTest.java create mode 100644 smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/JingleElementTest.java rename smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/{JingleErrorTest.java => JingleErrorElementTest.java} (76%) rename smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/{JingleReasonTest.java => JingleReasonElementTest.java} (60%) delete mode 100644 smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/JingleTest.java delete mode 100644 smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/JingleUtilTest.java create mode 100644 smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/component/JingleContentTest.java create mode 100644 smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/component/JingleSessionTest.java create mode 100644 smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/transport/JingleTransportComparatorTest.java create mode 100644 smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/transport/jingle_ibb/JingleIBBTransportTest.java create mode 100644 smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/JingleS5BTransportTest.java delete mode 100644 smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/transports/jingle_ibb/JingleIBBTransportTest.java delete mode 100644 smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/transports/jingle_s5b/JingleS5BTransportTest.java rename {smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer => smack-integration-test/src/main/java/org/jivesoftware/smackx/jingle}/package-info.java (79%) create mode 100644 smack-integration-test/src/main/java/org/jivesoftware/smackx/jingle/transport/JingleTransportIntegrationTest.java rename {smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_ibb => smack-integration-test/src/main/java/org/jivesoftware/smackx/jingle/transport}/package-info.java (77%) diff --git a/smack-core/src/main/java/org/jivesoftware/smack/util/ParserUtils.java b/smack-core/src/main/java/org/jivesoftware/smack/util/ParserUtils.java index 14a003a21..e795a83e0 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/util/ParserUtils.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/util/ParserUtils.java @@ -57,7 +57,7 @@ public class ParserUtils { } public static void forwardToEndTagOfDepth(XmlPullParser parser, int depth) - throws XmlPullParserException, IOException { + throws XmlPullParserException, IOException { int event = parser.getEventType(); while (!(event == XmlPullParser.END_TAG && parser.getDepth() == depth)) { event = parser.next(); @@ -107,7 +107,9 @@ public class ParserUtils { } Jid jid = JidCreate.from(jidString); - if (!jid.hasLocalpart()) return null; + if (!jid.hasLocalpart()) { + return null; + } EntityFullJid fullJid = jid.asEntityFullJidIfPossible(); if (fullJid != null) { @@ -128,32 +130,32 @@ public class ParserUtils { /** * Get the boolean value of an argument. - * + * * @param parser * @param name * @return the boolean value or null of no argument of the given name exists */ public static Boolean getBooleanAttribute(XmlPullParser parser, String name) { String valueString = parser.getAttributeValue("", name); - if (valueString == null) + if (valueString == null) { return null; + } + valueString = valueString.toLowerCase(Locale.US); if (valueString.equals("true") || valueString.equals("0")) { return true; - } else { - return false; } + + return false; } public static boolean getBooleanAttribute(XmlPullParser parser, String name, - boolean defaultValue) { + boolean defaultValue) { Boolean bool = getBooleanAttribute(parser, name); if (bool == null) { return defaultValue; } - else { - return bool; - } + return bool; } public static int getIntegerAttributeOrThrow(XmlPullParser parser, String name, String throwMessage) throws SmackException { @@ -166,8 +168,9 @@ public class ParserUtils { public static Integer getIntegerAttribute(XmlPullParser parser, String name) { String valueString = parser.getAttributeValue("", name); - if (valueString == null) + if (valueString == null) { return null; + } return Integer.valueOf(valueString); } @@ -176,9 +179,7 @@ public class ParserUtils { if (integer == null) { return defaultValue; } - else { - return integer; - } + return integer; } public static int getIntegerFromNextText(XmlPullParser parser) throws XmlPullParserException, IOException { @@ -188,8 +189,9 @@ public class ParserUtils { public static Long getLongAttribute(XmlPullParser parser, String name) { String valueString = parser.getAttributeValue("", name); - if (valueString == null) + if (valueString == null) { return null; + } return Long.valueOf(valueString); } @@ -198,9 +200,7 @@ public class ParserUtils { if (l == null) { return defaultValue; } - else { - return l; - } + return l; } public static double getDoubleFromNextText(XmlPullParser parser) throws XmlPullParserException, IOException { @@ -210,8 +210,9 @@ public class ParserUtils { public static Double getDoubleAttribute(XmlPullParser parser, String name) { String valueString = parser.getAttributeValue("", name); - if (valueString == null) + if (valueString == null) { return null; + } return Double.valueOf(valueString); } @@ -220,9 +221,23 @@ public class ParserUtils { if (d == null) { return defaultValue; } - else { - return d; + return d; + } + + public static Short getShortAttribute(XmlPullParser parser, String name) { + String valueString = parser.getAttributeValue("", name); + if (valueString == null) { + return null; } + return Short.valueOf(valueString); + } + + public static short getShortAttribute(XmlPullParser parser, String name, short defaultValue) { + Short s = getShortAttribute(parser, name); + if (s == null) { + return defaultValue; + } + return s; } public static Date getDateFromNextText(XmlPullParser parser) throws XmlPullParserException, IOException, ParseException { diff --git a/smack-core/src/main/java/org/jivesoftware/smack/util/XmlStringBuilder.java b/smack-core/src/main/java/org/jivesoftware/smack/util/XmlStringBuilder.java index 2579bf522..6ad888e98 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/util/XmlStringBuilder.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/util/XmlStringBuilder.java @@ -271,6 +271,11 @@ public class XmlStringBuilder implements Appendable, CharSequence { return attribute(name, String.valueOf(value)); } + public XmlStringBuilder attribute(String name, long value) { + assert name != null; + return attribute(name, String.valueOf(value)); + } + public XmlStringBuilder optAttribute(String name, String value) { if (value != null) { attribute(name, value); @@ -278,6 +283,13 @@ public class XmlStringBuilder implements Appendable, CharSequence { return this; } + public XmlStringBuilder optAttribute(String name, Long value) { + if (value != null) { + attribute(name, value); + } + return this; + } + /** * Add a new attribute to this builder, with the {@link java.util.Date} instance as its value, * which will get formated with {@link XmppDateTime#formatXEP0082Date(Date)} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/JingleFileTransferManager.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/JingleFileTransferManager.java deleted file mode 100644 index 7b96cdbd4..000000000 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/JingleFileTransferManager.java +++ /dev/null @@ -1,43 +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_filetransfer; - -import java.util.WeakHashMap; - -import org.jivesoftware.smack.Manager; -import org.jivesoftware.smack.XMPPConnection; - -/** - * Manager for JingleFileTransfer (XEP-0234). - */ -public final class JingleFileTransferManager extends Manager { - - private static final WeakHashMap INSTANCES = new WeakHashMap<>(); - - private JingleFileTransferManager(XMPPConnection connection) { - super(connection); - } - - public static JingleFileTransferManager getInstanceFor(XMPPConnection connection) { - JingleFileTransferManager manager = INSTANCES.get(connection); - if (manager == null) { - manager = new JingleFileTransferManager(connection); - INSTANCES.put(connection, manager); - } - return manager; - } -} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/element/Checksum.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/element/Checksum.java deleted file mode 100644 index a841c8ae7..000000000 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/element/Checksum.java +++ /dev/null @@ -1,63 +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_filetransfer.element; - -import org.jivesoftware.smack.packet.ExtensionElement; -import org.jivesoftware.smack.util.Objects; -import org.jivesoftware.smack.util.XmlStringBuilder; -import org.jivesoftware.smackx.jingle.element.JingleContent; - -/** - * Checksum element. - */ -public class Checksum implements ExtensionElement { - public static final String ELEMENT = "checksum"; - public static final String ATTR_CREATOR = "creator"; - public static final String ATTR_NAME = "name"; - - private final JingleContent.Creator creator; - private final String name; - private final JingleFileTransferChild file; - - public Checksum(JingleContent.Creator creator, String name, JingleFileTransferChild file) { - this.creator = creator; - this.name = name; - this.file = Objects.requireNonNull(file, "file MUST NOT be null."); - Objects.requireNonNull(file.getHash(), "file MUST contain at least one hash element."); - } - - @Override - public String getElementName() { - return ELEMENT; - } - - @Override - public CharSequence toXML() { - XmlStringBuilder sb = new XmlStringBuilder(this); - sb.optAttribute(ATTR_CREATOR, creator); - sb.optAttribute(ATTR_NAME, name); - sb.rightAngleBracket(); - sb.element(file); - sb.closeElement(this); - return sb; - } - - @Override - public String getNamespace() { - return JingleFileTransfer.NAMESPACE_V5; - } -} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/element/JingleFileTransferChild.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/element/JingleFileTransferChild.java deleted file mode 100644 index 9634d0a1b..000000000 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/element/JingleFileTransferChild.java +++ /dev/null @@ -1,167 +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_filetransfer.element; - -import java.io.File; -import java.util.Date; - -import org.jivesoftware.smack.util.XmlStringBuilder; -import org.jivesoftware.smackx.hashes.element.HashElement; -import org.jivesoftware.smackx.jingle.element.JingleContentDescriptionChildElement; - -/** - * Content of type File. - */ -public class JingleFileTransferChild extends JingleContentDescriptionChildElement { - public static final String ELEMENT = "file"; - public static final String ELEM_DATE = "date"; - public static final String ELEM_DESC = "desc"; - public static final String ELEM_MEDIA_TYPE = "media-type"; - public static final String ELEM_NAME = "name"; - public static final String ELEM_SIZE = "size"; - - private final Date date; - private final String desc; - private final HashElement hash; - private final String mediaType; - private final String name; - private final int size; - private final Range range; - - public JingleFileTransferChild(Date date, String desc, HashElement hash, String mediaType, String name, int size, Range range) { - this.date = date; - this.desc = desc; - this.hash = hash; - this.mediaType = mediaType; - this.name = name; - this.size = size; - this.range = range; - } - - public Date getDate() { - return date; - } - - public String getDescription() { - return desc; - } - - public HashElement getHash() { - return hash; - } - - public String getMediaType() { - return mediaType; - } - - public String getName() { - return name; - } - - public int getSize() { - return size; - } - - public Range getRange() { - return range; - } - - @Override - public String getElementName() { - return ELEMENT; - } - - @Override - public CharSequence toXML() { - XmlStringBuilder sb = new XmlStringBuilder(this); - sb.rightAngleBracket(); - - sb.optElement(ELEM_DATE, date); - sb.optElement(ELEM_DESC, desc); - sb.optElement(ELEM_MEDIA_TYPE, mediaType); - sb.optElement(ELEM_NAME, name); - sb.optElement(range); - if (size > 0) { - sb.element(ELEM_SIZE, Integer.toString(size)); - } - sb.optElement(hash); - sb.closeElement(this); - return sb; - } - - public static Builder getBuilder() { - return new Builder(); - } - - public static final class Builder { - private Date date; - private String desc; - private HashElement hash; - private String mediaType; - private String name; - private int size; - private Range range; - - private Builder() { - } - - public Builder setDate(Date date) { - this.date = date; - return this; - } - - public Builder setDescription(String desc) { - this.desc = desc; - return this; - } - - public Builder setHash(HashElement hash) { - this.hash = hash; - return this; - } - - public Builder setMediaType(String mediaType) { - this.mediaType = mediaType; - return this; - } - - public Builder setName(String name) { - this.name = name; - return this; - } - - public Builder setSize(int size) { - this.size = size; - return this; - } - - public Builder setRange(Range range) { - this.range = range; - return this; - } - - public JingleFileTransferChild build() { - return new JingleFileTransferChild(date, desc, hash, mediaType, name, size, range); - } - - public Builder setFile(File file) { - return setDate(new Date(file.lastModified())) - .setName(file.getAbsolutePath().substring(file.getAbsolutePath().lastIndexOf("/") + 1)) - .setSize((int) file.length()); - } - } -} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/element/Range.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/element/Range.java deleted file mode 100644 index 9d4f867ad..000000000 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/element/Range.java +++ /dev/null @@ -1,135 +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_filetransfer.element; - -import org.jivesoftware.smack.packet.NamedElement; -import org.jivesoftware.smack.util.XmlStringBuilder; -import org.jivesoftware.smackx.hashes.element.HashElement; - -/** - * RangeElement which specifies, which range of a file shall be transferred. - */ -public class Range implements NamedElement { - - public static final String ELEMENT = "range"; - public static final String ATTR_OFFSET = "offset"; - public static final String ATTR_LENGTH = "length"; - - private final int offset, length; - private final HashElement hash; - - /** - * Create a Range element with default values. - */ - public Range() { - this(0, -1, null); - } - - /** - * Create a Range element with specified length. - * @param length length of the transmitted data in bytes. - */ - public Range(int length) { - this(0, length, null); - } - - /** - * Create a Range element with specified offset and length. - * @param offset offset in bytes from the beginning of the transmitted data. - * @param length number of bytes that shall be transferred. - */ - public Range(int offset, int length) { - this(offset, length, null); - } - - /** - * Create a Range element with specified offset, length and hash. - * @param offset offset in bytes from the beginning of the transmitted data. - * @param length number of bytes that shall be transferred. - * @param hash hash of the bytes in the specified range. - */ - public Range(int offset, int length, HashElement hash) { - this.offset = offset; - this.length = length; - this.hash = hash; - } - - /** - * Return the index of the offset. - * This marks the begin of the specified range. - * @return offset - */ - public int getOffset() { - return offset; - } - - /** - * Return the length of the range. - * @return length - */ - public int getLength() { - return length; - } - - /** - * Return the hash element that contains a checksum of the bytes specified in the range. - * @return hash element - */ - public HashElement getHash() { - return hash; - } - - @Override - public String getElementName() { - return ELEMENT; - } - - @Override - public CharSequence toXML() { - XmlStringBuilder sb = new XmlStringBuilder(this); - - if (offset > 0) { - sb.attribute(ATTR_OFFSET, offset); - } - if (length > 0) { - sb.attribute(ATTR_LENGTH, length); - } - - if (hash != null) { - sb.rightAngleBracket(); - sb.element(hash); - sb.closeElement(this); - } else { - sb.closeEmptyElement(); - } - return sb; - } - - @Override - public boolean equals(Object other) { - if (other == null || !(other instanceof Range)) { - return false; - } - - return this.hashCode() == other.hashCode(); - } - - @Override - public int hashCode() { - return toXML().toString().hashCode(); - } -} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/provider/ChecksumProvider.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/provider/ChecksumProvider.java deleted file mode 100644 index 980b50a74..000000000 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/provider/ChecksumProvider.java +++ /dev/null @@ -1,90 +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_filetransfer.provider; - -import static org.xmlpull.v1.XmlPullParser.END_TAG; -import static org.xmlpull.v1.XmlPullParser.START_TAG; - -import org.jivesoftware.smack.provider.ExtensionElementProvider; -import org.jivesoftware.smackx.hashes.element.HashElement; -import org.jivesoftware.smackx.hashes.provider.HashElementProvider; -import org.jivesoftware.smackx.jingle.element.JingleContent; -import org.jivesoftware.smackx.jingle_filetransfer.element.Checksum; -import org.jivesoftware.smackx.jingle_filetransfer.element.JingleFileTransferChild; -import org.jivesoftware.smackx.jingle_filetransfer.element.Range; - -import org.xmlpull.v1.XmlPullParser; - -/** - * Provider for the Checksum element. - */ -public class ChecksumProvider extends ExtensionElementProvider { - @Override - public Checksum parse(XmlPullParser parser, int initialDepth) throws Exception { - JingleContent.Creator creator = null; - String creatorString = parser.getAttributeValue(null, Checksum.ATTR_CREATOR); - if (creatorString != null) { - creator = JingleContent.Creator.valueOf(creatorString); - } - String name = parser.getAttributeValue(null, Checksum.ATTR_NAME); - - - JingleFileTransferChild.Builder cb = JingleFileTransferChild.getBuilder(); - HashElement hashElement = null; - Range range = null; - - boolean go = true; - while (go) { - int tag = parser.nextTag(); - String n = parser.getText(); - - if (tag == START_TAG) { - switch (n) { - case HashElement.ELEMENT: - hashElement = new HashElementProvider().parse(parser); - break; - - case Range.ELEMENT: - String offset = parser.getAttributeValue(null, Range.ATTR_OFFSET); - String length = parser.getAttributeValue(null, Range.ATTR_LENGTH); - int o = offset == null ? 0 : Integer.parseInt(offset); - int l = length == null ? -1 : Integer.parseInt(length); - range = new Range(o, l); - } - } else if (tag == END_TAG) { - switch (n) { - case Range.ELEMENT: - if (hashElement != null && range != null) { - range = new Range(range.getOffset(), range.getLength(), hashElement); - hashElement = null; - } - break; - - case JingleFileTransferChild.ELEMENT: - if (hashElement != null) { - cb.setHash(hashElement); - } - if (range != null) { - cb.setRange(range); - } - go = false; - } - } - } - return new Checksum(creator, name, cb.build()); - } -} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/provider/JingleFileTransferProvider.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/provider/JingleFileTransferProvider.java deleted file mode 100644 index 8570188a6..000000000 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/provider/JingleFileTransferProvider.java +++ /dev/null @@ -1,120 +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_filetransfer.provider; - -import static org.xmlpull.v1.XmlPullParser.END_TAG; -import static org.xmlpull.v1.XmlPullParser.START_TAG; - -import java.util.ArrayList; - -import org.jivesoftware.smackx.hashes.element.HashElement; -import org.jivesoftware.smackx.hashes.provider.HashElementProvider; -import org.jivesoftware.smackx.jingle.element.JingleContentDescriptionChildElement; -import org.jivesoftware.smackx.jingle.provider.JingleContentDescriptionProvider; -import org.jivesoftware.smackx.jingle_filetransfer.element.JingleFileTransfer; -import org.jivesoftware.smackx.jingle_filetransfer.element.JingleFileTransferChild; -import org.jivesoftware.smackx.jingle_filetransfer.element.Range; - -import org.jxmpp.util.XmppDateTime; -import org.xmlpull.v1.XmlPullParser; - -/** - * Provider for JingleContentDescriptionFileTransfer elements. - */ -public class JingleFileTransferProvider - extends JingleContentDescriptionProvider { - - @Override - public JingleFileTransfer parse(XmlPullParser parser, int initialDepth) throws Exception { - ArrayList payloads = new ArrayList<>(); - boolean inRange = false; - JingleFileTransferChild.Builder builder = JingleFileTransferChild.getBuilder(); - HashElement inRangeHash = null; - - int offset = 0; - int length = -1; - - while (true) { - - int tag = parser.nextTag(); - String elem = parser.getName(); - - if (tag == START_TAG) { - switch (elem) { - case JingleFileTransferChild.ELEM_DATE: - builder.setDate(XmppDateTime.parseXEP0082Date(parser.nextText())); - break; - - case JingleFileTransferChild.ELEM_DESC: - builder.setDescription(parser.nextText()); - break; - - case JingleFileTransferChild.ELEM_MEDIA_TYPE: - builder.setMediaType(parser.nextText()); - break; - - case JingleFileTransferChild.ELEM_NAME: - builder.setName(parser.nextText()); - break; - - case JingleFileTransferChild.ELEM_SIZE: - builder.setSize(Integer.parseInt(parser.nextText())); - break; - - case Range.ELEMENT: - inRange = true; - String offsetString = parser.getAttributeValue(null, Range.ATTR_OFFSET); - String lengthString = parser.getAttributeValue(null, Range.ATTR_LENGTH); - offset = (offsetString != null ? Integer.parseInt(offsetString) : 0); - length = (lengthString != null ? Integer.parseInt(lengthString) : -1); - - if (parser.isEmptyElementTag()) { - inRange = false; - builder.setRange(new Range(offset, length)); - } - break; - - case HashElement.ELEMENT: - if (inRange) { - inRangeHash = new HashElementProvider().parse(parser); - } else { - builder.setHash(new HashElementProvider().parse(parser)); - } - break; - } - - } else if (tag == END_TAG) { - switch (elem) { - - case Range.ELEMENT: - inRange = false; - builder.setRange(new Range(offset, length, inRangeHash)); - inRangeHash = null; - break; - - case JingleFileTransferChild.ELEMENT: - payloads.add(builder.build()); - builder = JingleFileTransferChild.getBuilder(); - break; - - case JingleFileTransfer.ELEMENT: - return new JingleFileTransfer(payloads); - } - } - } - } -} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5Proxy.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5Proxy.java index f7e89270a..d12157801 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5Proxy.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5Proxy.java @@ -361,7 +361,7 @@ public final class Socks5Proxy { * * @param digest to be removed from the list of allowed transfers */ - protected void removeTransfer(String digest) { + public void removeTransfer(String digest) { this.allowedConnections.remove(digest); this.connectionMap.remove(digest); } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/packet/Bytestream.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/packet/Bytestream.java index 8b022d9fc..2ed7885b3 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/packet/Bytestream.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/packet/Bytestream.java @@ -455,4 +455,26 @@ public class Bytestream extends IQ { return mode; } } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + + if (!(other instanceof Bytestream)) { + return false; + } + + Bytestream o = (Bytestream) other; + + return o.getMode() == getMode() && + o.getSessionID().equals(getSessionID()) && + o.getStreamHosts().equals(getStreamHosts()); + } + + @Override + public int hashCode() { + return 31 * getStreamHosts().hashCode() + 29 * getSessionID().hashCode() + 23 * getMode().hashCode(); + } } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleHandler.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleDescriptionController.java similarity index 56% rename from smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleHandler.java rename to smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleDescriptionController.java index 2322a06ac..609b1b6d3 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleHandler.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleDescriptionController.java @@ -1,6 +1,6 @@ /** * - * Copyright 2017 Florian Schmaus + * 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. @@ -16,11 +16,18 @@ */ package org.jivesoftware.smackx.jingle; -import org.jivesoftware.smack.packet.IQ; -import org.jivesoftware.smackx.jingle.element.Jingle; +/** + * Created by vanitas on 27.07.17. + */ +public interface JingleDescriptionController { -public interface JingleHandler { - - IQ handleJingleRequest(Jingle jingle); + enum State { + pending, //Not yet accepted by us/peer + negotiating, //Accepted, but still negotiating transports etc. + active, //Bytestream initialized and active + cancelled, //We/Peer cancelled the transmission + ended //Successfully ended + } + State getState(); } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleSessionHandler.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleDescriptionManager.java similarity index 60% rename from smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleSessionHandler.java rename to smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleDescriptionManager.java index a57ede3ff..affc24080 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleSessionHandler.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleDescriptionManager.java @@ -1,6 +1,6 @@ /** * - * Copyright 2017 Florian Schmaus + * 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. @@ -16,11 +16,17 @@ */ package org.jivesoftware.smackx.jingle; -import org.jivesoftware.smack.packet.IQ; -import org.jivesoftware.smackx.jingle.element.Jingle; +import org.jivesoftware.smackx.jingle.component.JingleContent; +import org.jivesoftware.smackx.jingle.component.JingleSession; -public interface JingleSessionHandler { +/** + * Manager for JingleDescription components. + */ +public interface JingleDescriptionManager { - IQ handleJingleSessionRequest(Jingle jingle); + String getNamespace(); + void notifySessionInitiate(JingleSession session); + + void notifyContentAdd(JingleSession session, JingleContent content); } 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 552a018ef..36e0c550e 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 @@ -1,6 +1,6 @@ /** * - * Copyright 2017 Florian Schmaus + * 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. @@ -16,119 +16,272 @@ */ package org.jivesoftware.smackx.jingle; -import java.util.Map; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Set; import java.util.WeakHashMap; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import java.util.logging.Level; import java.util.logging.Logger; import org.jivesoftware.smack.Manager; +import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.XMPPConnection; +import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.iqrequest.AbstractIqRequestHandler; -import org.jivesoftware.smack.iqrequest.IQRequestHandler.Mode; +import org.jivesoftware.smack.iqrequest.IQRequestHandler; import org.jivesoftware.smack.packet.IQ; -import org.jivesoftware.smack.packet.IQ.Type; import org.jivesoftware.smack.util.StringUtils; -import org.jivesoftware.smackx.jingle.element.Jingle; +import org.jivesoftware.smackx.disco.ServiceDiscoveryManager; +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.component.JingleSession; 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.jivesoftware.smackx.jingle.element.JingleElement; +import org.jivesoftware.smackx.jingle.element.JingleReasonElement; +import org.jivesoftware.smackx.jingle.exception.UnsupportedDescriptionException; +import org.jivesoftware.smackx.jingle.exception.UnsupportedSecurityException; +import org.jivesoftware.smackx.jingle.exception.UnsupportedTransportException; +import org.jivesoftware.smackx.jingle.provider.JingleContentDescriptionProvider; +import org.jivesoftware.smackx.jingle.provider.JingleContentSecurityProvider; +import org.jivesoftware.smackx.jingle.provider.JingleContentTransportProvider; +import org.jivesoftware.smackx.jingle.util.FullJidAndSessionId; +import org.jivesoftware.smackx.jingle.util.Role; import org.jxmpp.jid.FullJid; +import org.jxmpp.jid.Jid; +/** + * Manager for Jingle (XEP-0166). + */ public final class JingleManager extends Manager { - private static final Logger LOGGER = Logger.getLogger(JingleManager.class.getName()); + private static final WeakHashMap INSTANCES = new WeakHashMap<>(); - private static final Map INSTANCES = new WeakHashMap<>(); + private static final WeakHashMap> descriptionProviders = new WeakHashMap<>(); + private static final WeakHashMap> transportProviders = new WeakHashMap<>(); + private static final WeakHashMap> securityProviders = new WeakHashMap<>(); - private static final ExecutorService threadPool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); + private static final WeakHashMap> descriptionAdapters = new WeakHashMap<>(); + private static final WeakHashMap> transportAdapters = new WeakHashMap<>(); + private static final WeakHashMap> securityAdapters = new WeakHashMap<>(); - public static ExecutorService getThreadPool() { - return threadPool; - } + private final WeakHashMap descriptionManagers = new WeakHashMap<>(); + private final WeakHashMap transportManagers = new WeakHashMap<>(); + private final WeakHashMap securityManagers = new WeakHashMap<>(); - public static synchronized JingleManager getInstanceFor(XMPPConnection connection) { - JingleManager jingleManager = INSTANCES.get(connection); - if (jingleManager == null) { - jingleManager = new JingleManager(connection); - INSTANCES.put(connection, jingleManager); - } - return jingleManager; - } + private final ConcurrentHashMap jingleSessions = new ConcurrentHashMap<>(); - private final Map descriptionHandlers = new ConcurrentHashMap<>(); - - private final Map jingleSessionHandlers = new ConcurrentHashMap<>(); - - private final JingleUtil jutil; - - private JingleManager(XMPPConnection connection) { + private JingleManager(final XMPPConnection connection) { super(connection); - jutil = new JingleUtil(connection); - connection.registerIQRequestHandler( - new AbstractIqRequestHandler(Jingle.ELEMENT, Jingle.NAMESPACE, Type.set, Mode.async) { + new AbstractIqRequestHandler(JingleElement.ELEMENT, JingleElement.NAMESPACE, IQ.Type.set, IQRequestHandler.Mode.async) { @Override public IQ handleIQRequest(IQ iqRequest) { - final Jingle jingle = (Jingle) iqRequest; + final JingleElement jingle = (JingleElement) iqRequest; FullJid fullFrom = jingle.getFrom().asFullJidOrThrow(); String sid = jingle.getSid(); FullJidAndSessionId fullJidAndSessionId = new FullJidAndSessionId(fullFrom, sid); - JingleSessionHandler sessionHandler = jingleSessionHandlers.get(fullJidAndSessionId); - if (sessionHandler != null) { - //Handle existing session - return sessionHandler.handleJingleSessionRequest(jingle); - } + JingleSession session = jingleSessions.get(fullJidAndSessionId); - if (jingle.getAction() == JingleAction.session_initiate) { + // We have not seen this session before. + // Either it is fresh, or unknown. + if (session == null) { + LOGGER.log(Level.INFO, connection().getUser().asFullJidOrThrow() + " received unknown session: " + jingle.getFrom().asFullJidOrThrow() + " " + jingle.getSid()); + if (jingle.getAction() == JingleAction.session_initiate) { + //fresh. phew! + try { + session = JingleSession.fromSessionInitiate(JingleManager.this, jingle); + jingleSessions.put(fullJidAndSessionId, session); + } catch (UnsupportedDescriptionException e) { + return JingleElement.createSessionTerminate(jingle.getFrom().asFullJidOrThrow(), + jingle.getSid(), JingleReasonElement.Reason.unsupported_applications); + } catch (UnsupportedTransportException e) { + return JingleElement.createSessionTerminate(jingle.getFrom().asFullJidOrThrow(), + jingle.getSid(), JingleReasonElement.Reason.unsupported_transports); + } catch (UnsupportedSecurityException e) { + LOGGER.log(Level.SEVERE, "Unsupported Security: " + e, e); + return null; + } - JingleContent content = jingle.getContents().get(0); - JingleContentDescription description = content.getDescription(); - JingleHandler jingleDescriptionHandler = descriptionHandlers.get( - description.getNamespace()); - - if (jingleDescriptionHandler == null) { - //Unsupported Application - LOGGER.log(Level.WARNING, "Unsupported Jingle application."); - return jutil.createSessionTerminateUnsupportedApplications(fullFrom, sid); + } else { + // Unknown session. Error! + return JingleElement.createJingleErrorUnknownSession(jingle); } - return jingleDescriptionHandler.handleJingleRequest(jingle); } - //Unknown session - LOGGER.log(Level.WARNING, "Unknown session."); - return jutil.createErrorUnknownSession(jingle); + return session.handleJingleRequest(jingle); } }); - //Register transports. - JingleTransportMethodManager transportMethodManager = JingleTransportMethodManager.getInstanceFor(connection); - transportMethodManager.registerTransportManager(JingleIBBTransportManager.getInstanceFor(connection)); - transportMethodManager.registerTransportManager(JingleS5BTransportManager.getInstanceFor(connection)); } - public JingleHandler registerDescriptionHandler(String namespace, JingleHandler handler) { - return descriptionHandlers.put(namespace, handler); + public static JingleManager getInstanceFor(XMPPConnection connection) { + JingleManager manager = INSTANCES.get(connection); + + if (manager == null) { + manager = new JingleManager(connection); + INSTANCES.put(connection, manager); + } + + return manager; } - public JingleSessionHandler registerJingleSessionHandler(FullJid otherJid, String sessionId, JingleSessionHandler sessionHandler) { - FullJidAndSessionId fullJidAndSessionId = new FullJidAndSessionId(otherJid, sessionId); - return jingleSessionHandlers.put(fullJidAndSessionId, sessionHandler); + public static void addJingleDescriptionAdapter(JingleDescriptionAdapter adapter) { + descriptionAdapters.put(adapter.getNamespace(), adapter); } - public JingleSessionHandler unregisterJingleSessionHandler(FullJid otherJid, String sessionId, JingleSessionHandler sessionHandler) { - FullJidAndSessionId fullJidAndSessionId = new FullJidAndSessionId(otherJid, sessionId); - return jingleSessionHandlers.remove(fullJidAndSessionId); + public static void addJingleTransportAdapter(JingleTransportAdapter adapter) { + transportAdapters.put(adapter.getNamespace(), adapter); } - public static String randomId() { - return StringUtils.randomString(24); + public static void addJingleSecurityAdapter(JingleSecurityAdapter adapter) { + securityAdapters.put(adapter.getNamespace(), adapter); + } + + public static JingleDescriptionAdapter getJingleDescriptionAdapter(String namespace) { + return descriptionAdapters.get(namespace); + } + + public static JingleTransportAdapter getJingleTransportAdapter(String namespace) { + return transportAdapters.get(namespace); + } + + public static JingleSecurityAdapter getJingleSecurityAdapter(String namespace) { + return securityAdapters.get(namespace); + } + + public static void addJingleDescriptionProvider(JingleContentDescriptionProvider provider) { + descriptionProviders.put(provider.getNamespace(), provider); + } + + public static void removeJingleDescriptionProvider(String namespace) { + descriptionProviders.remove(namespace); + } + + public static JingleContentDescriptionProvider getJingleDescriptionProvider(String namespace) { + return descriptionProviders.get(namespace); + } + + public static void addJingleTransportProvider(JingleContentTransportProvider provider) { + transportProviders.put(provider.getNamespace(), provider); + } + + public static void removeJingleTransportProvider(String namespace) { + transportProviders.remove(namespace); + } + + public static JingleContentTransportProvider getJingleTransportProvider(String namespace) { + return transportProviders.get(namespace); + } + + public static void addJingleSecurityProvider(JingleContentSecurityProvider provider) { + securityProviders.put(provider.getNamespace(), provider); + } + + public static void removeJingleSecurityProvider(String namespace) { + securityProviders.remove(namespace); + } + + public static JingleContentSecurityProvider getJingleSecurityProvider(String namespace) { + return securityProviders.get(namespace); + } + + public void addJingleDescriptionManager(JingleDescriptionManager manager) { + descriptionManagers.put(manager.getNamespace(), manager); + } + + public JingleDescriptionManager getDescriptionManager(String namespace) { + return descriptionManagers.get(namespace); + } + + public void addJingleTransportManager(JingleTransportManager manager) { + transportManagers.put(manager.getNamespace(), manager); + } + + public JingleTransportManager getTransportManager(String namespace) { + return transportManagers.get(namespace); + } + + public void addJingleSecurityManager(JingleSecurityManager manager) { + securityManagers.put(manager.getNamespace(), manager); + } + + public JingleSecurityManager getSecurityManager(String namespace) { + return securityManagers.get(namespace); + } + + public List getAvailableTransportManagers(Jid to) throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException { + return getAvailableTransportManagers(to, Collections.emptySet()); + } + + public List getAvailableTransportManagers(Jid to, Set except) throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException { + Set available = new HashSet<>(transportManagers.keySet()); + available.removeAll(except); + List remaining = new ArrayList<>(); + + for (String namespace : available) { + if (ServiceDiscoveryManager.getInstanceFor(connection()).supportsFeature(to, namespace)) { + remaining.add(transportManagers.get(namespace)); + } + } + + Collections.sort(remaining, new Comparator() { + @Override + public int compare(JingleTransportManager t0, JingleTransportManager t1) { + return t1.compareTo(t0); //Invert otherwise ascending order to descending. + } + }); + + return remaining; + } + + public JingleTransportManager getBestAvailableTransportManager(Jid to) throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException { + return getBestAvailableTransportManager(to, Collections.emptySet()); + } + + public JingleTransportManager getBestAvailableTransportManager(Jid to, Set except) throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException { + List managers = getAvailableTransportManagers(to, except); + + if (managers.size() > 0) { + return managers.get(0); + } + + return null; + } + + public XMPPConnection getConnection() { + return connection(); + } + + public JingleSession createSession(Role role, FullJid peer) { + JingleSession session; + + if (role == Role.initiator) { + session = new JingleSession(this, connection().getUser().asFullJidOrThrow(), peer, + role, StringUtils.randomString(24)); + } else { + session = new JingleSession(this, peer, connection().getUser().asFullJidOrThrow(), + role, StringUtils.randomString(24)); + } + + jingleSessions.put(new FullJidAndSessionId(peer, session.getSessionId()), session); + return session; + } + + public void addSession(JingleSession session) { + if (!jingleSessions.containsValue(session)) { + jingleSessions.put(new FullJidAndSessionId(session.getPeer(), session.getSessionId()), session); + } + } + + public void removeSession(JingleSession session) { + jingleSessions.remove(new FullJidAndSessionId(session.getPeer(), session.getSessionId())); } } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleSecurityManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleSecurityManager.java new file mode 100644 index 000000000..4637464d2 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleSecurityManager.java @@ -0,0 +1,25 @@ +/** + * + * 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; + +/** + * Manager for JingleSecurity components. + */ +public interface JingleSecurityManager { + + String getNamespace(); +} 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 deleted file mode 100644 index 1ae4ac650..000000000 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleSession.java +++ /dev/null @@ -1,230 +0,0 @@ -/** - * - * Copyright 2017 Florian Schmaus - * - * 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 java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.concurrent.Future; - -import org.jivesoftware.smack.XMPPConnection; -import org.jivesoftware.smack.packet.IQ; -import org.jivesoftware.smackx.jingle.element.Jingle; -import org.jivesoftware.smackx.jingle.element.JingleContent; -import org.jivesoftware.smackx.jingle.transports.JingleTransportSession; - -import org.jxmpp.jid.FullJid; - -public abstract class JingleSession implements JingleSessionHandler { - protected HashSet failedTransportMethods = new HashSet<>(); - - protected final FullJid local; - - protected final FullJid remote; - - protected final Role role; - - protected final String sid; - - protected final List contents = new ArrayList<>(); - - protected ArrayList> queued = new ArrayList<>(); - protected JingleTransportSession transportSession; - - public JingleSession(FullJid initiator, FullJid responder, Role role, String sid) { - this(initiator, responder, role, sid, null); - } - - public JingleSession(FullJid initiator, FullJid responder, Role role, String sid, List contents) { - if (role == Role.initiator) { - this.local = initiator; - this.remote = responder; - } else { - this.local = responder; - this.remote = initiator; - } - this.sid = sid; - this.role = role; - - if (contents != null) { - this.contents.addAll(contents); - } - } - - public FullJid getInitiator() { - return isInitiator() ? local : remote; - } - - public boolean isInitiator() { - return role == Role.initiator; - } - - public FullJid getResponder() { - return isResponder() ? local : remote; - } - - public boolean isResponder() { - return role == Role.responder; - } - - public FullJid getRemote() { - return remote; - } - - public FullJid getLocal() { - return local; - } - - public String getSessionId() { - return sid; - } - - public FullJidAndSessionId getFullJidAndSessionId() { - return new FullJidAndSessionId(remote, sid); - } - - public List getContents() { - return contents; - } - - public JingleTransportSession getTransportSession() { - return transportSession; - } - - protected void setTransportSession(JingleTransportSession transportSession) { - this.transportSession = transportSession; - } - - @Override - public int hashCode() { - int hashCode = 31 + getInitiator().hashCode(); - hashCode = 31 * hashCode + getResponder().hashCode(); - hashCode = 31 * hashCode + getSessionId().hashCode(); - return hashCode; - } - - @Override - public boolean equals(Object other) { - if (!(other instanceof JingleSession)) { - return false; - } - - JingleSession otherJingleSession = (JingleSession) other; - return getInitiator().equals(otherJingleSession.getInitiator()) - && getResponder().equals(otherJingleSession.getResponder()) - && sid.equals(otherJingleSession.sid); - } - - @Override - public IQ handleJingleSessionRequest(Jingle jingle) { - switch (jingle.getAction()) { - case content_accept: - return handleContentAccept(jingle); - case content_add: - return handleContentAdd(jingle); - case content_modify: - return handleContentModify(jingle); - case content_reject: - return handleContentReject(jingle); - case content_remove: - return handleContentRemove(jingle); - case description_info: - return handleDescriptionInfo(jingle); - case session_info: - return handleSessionInfo(jingle); - case security_info: - return handleSecurityInfo(jingle); - case session_accept: - return handleSessionAccept(jingle); - case transport_accept: - return handleTransportAccept(jingle); - case transport_info: - return transportSession.handleTransportInfo(jingle); - case session_initiate: - return handleSessionInitiate(jingle); - case transport_reject: - return handleTransportReject(jingle); - case session_terminate: - return handleSessionTerminate(jingle); - case transport_replace: - return handleTransportReplace(jingle); - default: - return IQ.createResultIQ(jingle); - } - } - - protected IQ handleSessionInitiate(Jingle sessionInitiate) { - return IQ.createResultIQ(sessionInitiate); - } - - protected IQ handleSessionTerminate(Jingle sessionTerminate) { - return IQ.createResultIQ(sessionTerminate); - } - - protected IQ handleSessionInfo(Jingle sessionInfo) { - return IQ.createResultIQ(sessionInfo); - } - - protected IQ handleSessionAccept(Jingle sessionAccept) { - return IQ.createResultIQ(sessionAccept); - } - - protected IQ handleContentAdd(Jingle contentAdd) { - return IQ.createResultIQ(contentAdd); - } - - protected IQ handleContentAccept(Jingle contentAccept) { - return IQ.createResultIQ(contentAccept); - } - - protected IQ handleContentModify(Jingle contentModify) { - return IQ.createResultIQ(contentModify); - } - - protected IQ handleContentReject(Jingle contentReject) { - return IQ.createResultIQ(contentReject); - } - - protected IQ handleContentRemove(Jingle contentRemove) { - return IQ.createResultIQ(contentRemove); - } - - protected IQ handleDescriptionInfo(Jingle descriptionInfo) { - return IQ.createResultIQ(descriptionInfo); - } - - protected IQ handleSecurityInfo(Jingle securityInfo) { - return IQ.createResultIQ(securityInfo); - } - - protected IQ handleTransportAccept(Jingle transportAccept) { - return IQ.createResultIQ(transportAccept); - } - - protected IQ handleTransportReplace(Jingle transportReplace) { - return IQ.createResultIQ(transportReplace); - } - - protected IQ handleTransportReject(Jingle transportReject) { - return IQ.createResultIQ(transportReject); - } - - public abstract XMPPConnection getConnection(); - - public abstract void onTransportMethodFailed(String namespace); - -} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleTransportManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleTransportManager.java new file mode 100644 index 000000000..89aa366ce --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleTransportManager.java @@ -0,0 +1,42 @@ +/** + * + * 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.smackx.jingle.component.JingleContent; +import org.jivesoftware.smackx.jingle.component.JingleTransport; +import org.jivesoftware.smackx.jingle.element.JingleContentTransportElement; + +/** + * Manager for JingleTransport components. + */ +public interface JingleTransportManager extends Comparable { + + String getNamespace(); + + JingleTransport createTransportForInitiator(JingleContent content); + + JingleTransport createTransportForResponder(JingleContent content, JingleTransport peersTransport); + + JingleTransport createTransportForResponder(JingleContent content, JingleContentTransportElement peersTransportElement); + + /** + * Return a (usually) positive integer, which is used to define a strict order over the set of available transport + * managers. + * @return priority. + */ + int getPriority(); +} 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 deleted file mode 100644 index 848dc1671..000000000 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleTransportMethodManager.java +++ /dev/null @@ -1,132 +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; - -import java.util.HashMap; -import java.util.Iterator; -import java.util.Set; -import java.util.WeakHashMap; - -import org.jivesoftware.smack.Manager; -import org.jivesoftware.smack.XMPPConnection; -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.JingleTransportManager; -import org.jivesoftware.smackx.jingle.transports.jingle_ibb.element.JingleIBBTransport; -import org.jivesoftware.smackx.jingle.transports.jingle_s5b.elements.JingleS5BTransport; - -/** - * Manager where TransportMethods are registered. - */ -public final class JingleTransportMethodManager extends Manager { - - private static final WeakHashMap INSTANCES = new WeakHashMap<>(); - - private final HashMap> transportManagers = new HashMap<>(); - - private static final String[] transportPreference = new String[] { - JingleS5BTransport.NAMESPACE_V1, - JingleIBBTransport.NAMESPACE_V1 - }; - - private JingleTransportMethodManager(XMPPConnection connection) { - super(connection); - } - - public static JingleTransportMethodManager getInstanceFor(XMPPConnection connection) { - JingleTransportMethodManager manager = INSTANCES.get(connection); - if (manager == null) { - manager = new JingleTransportMethodManager(connection); - INSTANCES.put(connection, manager); - } - return manager; - } - - public void registerTransportManager(JingleTransportManager 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); - if (content == null) { - return null; - } - - JingleContentTransport transport = content.getTransport(); - if (transport == null) { - return null; - } - - return getTransportManager(transport.getNamespace()); - } - - public static JingleTransportManager getBestAvailableTransportManager(XMPPConnection connection) { - return getInstanceFor(connection).getBestAvailableTransportManager(); - } - - public JingleTransportManager getBestAvailableTransportManager() { - JingleTransportManager tm; - for (String ns : transportPreference) { - tm = getTransportManager(ns); - if (tm != null) { - return tm; - } - } - - Iterator it = transportManagers.keySet().iterator(); - if (it.hasNext()) { - return getTransportManager(it.next()); - } - - return null; - } - - public JingleTransportManager getBestAvailableTransportManager(Set except) { - JingleTransportManager tm; - for (String ns : transportPreference) { - tm = getTransportManager(ns); - if (tm != null) { - if (except.contains(tm.getNamespace())) { - continue; - } - return tm; - } - } - - for (String ns : transportManagers.keySet()) { - if (except.contains(ns)) { - continue; - } - return getTransportManager(ns); - } - - return null; - } -} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleUtil.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleUtil.java deleted file mode 100644 index 9cad9a9da..000000000 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleUtil.java +++ /dev/null @@ -1,490 +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; - -import org.jivesoftware.smack.SmackException; -import org.jivesoftware.smack.XMPPConnection; -import org.jivesoftware.smack.XMPPException; -import org.jivesoftware.smack.packet.IQ; -import org.jivesoftware.smack.packet.XMPPError; -import org.jivesoftware.smackx.jingle.element.Jingle; -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.element.JingleContentTransport; -import org.jivesoftware.smackx.jingle.element.JingleError; -import org.jivesoftware.smackx.jingle.element.JingleReason; - -import org.jxmpp.jid.FullJid; - -/** - * Util to quickly create and send jingle stanzas. - */ -public class JingleUtil { - - private final XMPPConnection connection; - - public JingleUtil(XMPPConnection connection) { - this.connection = connection; - } - - public Jingle createSessionInitiate(FullJid recipient, - String sessionId, - JingleContent.Creator contentCreator, - String contentName, - JingleContent.Senders contentSenders, - JingleContentDescription description, - JingleContentTransport transport) { - - Jingle.Builder jb = Jingle.getBuilder(); - jb.setAction(JingleAction.session_initiate) - .setSessionId(sessionId) - .setInitiator(connection.getUser()); - - JingleContent.Builder cb = JingleContent.getBuilder(); - cb.setCreator(contentCreator) - .setName(contentName) - .setSenders(contentSenders) - .setDescription(description) - .setTransport(transport); - - Jingle jingle = jb.addJingleContent(cb.build()).build(); - jingle.setFrom(connection.getUser()); - jingle.setTo(recipient); - - return jingle; - } - - public Jingle createSessionInitiateFileOffer(FullJid recipient, - String sessionId, - JingleContent.Creator contentCreator, - String contentName, - JingleContentDescription description, - JingleContentTransport transport) { - return createSessionInitiate(recipient, sessionId, contentCreator, contentName, - JingleContent.Senders.initiator, description, transport); - } - - public IQ sendSessionInitiateFileOffer(FullJid recipient, - String sessionId, - JingleContent.Creator contentCreator, - String contentName, - JingleContentDescription description, - JingleContentTransport transport) - throws SmackException.NotConnectedException, InterruptedException, - XMPPException.XMPPErrorException, SmackException.NoResponseException { - - Jingle jingle = createSessionInitiateFileOffer(recipient, sessionId, contentCreator, contentName, description, transport); - return connection.createStanzaCollectorAndSend(jingle).nextResultOrThrow(); - } - - public IQ sendSessionInitiate(FullJid recipient, - String sessionId, - JingleContent.Creator contentCreator, - String contentName, - JingleContent.Senders contentSenders, - JingleContentDescription description, - JingleContentTransport transport) - throws SmackException.NotConnectedException, InterruptedException { - - Jingle jingle = createSessionInitiate(recipient, sessionId, contentCreator, contentName, contentSenders, - description, transport); - - return connection.createStanzaCollectorAndSend(jingle).nextResult(); - } - - public Jingle createSessionAccept(FullJid recipient, - String sessionId, - JingleContent.Creator contentCreator, - String contentName, - JingleContent.Senders contentSenders, - JingleContentDescription description, - JingleContentTransport transport) { - - Jingle.Builder jb = Jingle.getBuilder(); - jb.setResponder(connection.getUser()) - .setAction(JingleAction.session_accept) - .setSessionId(sessionId); - - JingleContent.Builder cb = JingleContent.getBuilder(); - cb.setCreator(contentCreator) - .setName(contentName) - .setSenders(contentSenders) - .setDescription(description) - .setTransport(transport); - - Jingle jingle = jb.addJingleContent(cb.build()).build(); - jingle.setTo(recipient); - jingle.setFrom(connection.getUser()); - - return jingle; - } - - public IQ sendSessionAccept(FullJid recipient, - String sessionId, - JingleContent.Creator contentCreator, - String contentName, - JingleContent.Senders contentSenders, - JingleContentDescription description, - JingleContentTransport transport) - throws SmackException.NotConnectedException, InterruptedException { - - Jingle jingle = createSessionAccept(recipient, sessionId, contentCreator, contentName, contentSenders, - description, transport); - - return connection.createStanzaCollectorAndSend(jingle).nextResult(); - } - - public Jingle createSessionTerminate(FullJid recipient, String sessionId, JingleReason reason) { - Jingle.Builder jb = Jingle.getBuilder(); - jb.setAction(JingleAction.session_terminate) - .setSessionId(sessionId) - .setReason(reason); - - Jingle jingle = jb.build(); - jingle.setFrom(connection.getUser()); - jingle.setTo(recipient); - - return jingle; - } - - public Jingle createSessionTerminate(FullJid recipient, String sessionId, JingleReason.Reason reason) { - return createSessionTerminate(recipient, sessionId, new JingleReason(reason)); - } - - public Jingle createSessionTerminateDecline(FullJid recipient, String sessionId) { - return createSessionTerminate(recipient, sessionId, JingleReason.Reason.decline); - } - - public IQ sendSessionTerminateDecline(FullJid recipient, String sessionId) - throws SmackException.NotConnectedException, InterruptedException, - XMPPException.XMPPErrorException, SmackException.NoResponseException { - - Jingle jingle = createSessionTerminateDecline(recipient, sessionId); - return connection.createStanzaCollectorAndSend(jingle).nextResultOrThrow(); - } - - public Jingle createSessionTerminateSuccess(FullJid recipient, String sessionId) { - return createSessionTerminate(recipient, sessionId, JingleReason.Reason.success); - } - - public IQ sendSessionTerminateSuccess(FullJid recipient, String sessionId) - throws InterruptedException, XMPPException.XMPPErrorException, - SmackException.NotConnectedException, SmackException.NoResponseException { - - Jingle jingle = createSessionTerminateSuccess(recipient, sessionId); - return connection.createStanzaCollectorAndSend(jingle).nextResultOrThrow(); - } - - public Jingle createSessionTerminateBusy(FullJid recipient, String sessionId) { - return createSessionTerminate(recipient, sessionId, JingleReason.Reason.busy); - } - - public IQ sendSessionTerminateBusy(FullJid recipient, String sessionId) - throws InterruptedException, XMPPException.XMPPErrorException, - SmackException.NotConnectedException, SmackException.NoResponseException { - - Jingle jingle = createSessionTerminateBusy(recipient, sessionId); - return connection.createStanzaCollectorAndSend(jingle).nextResultOrThrow(); - } - - public Jingle createSessionTerminateAlternativeSession(FullJid recipient, String sessionId, String altSessionId) { - return createSessionTerminate(recipient, sessionId, JingleReason.AlternativeSession(altSessionId)); - } - - public IQ sendSessionTerminateAlternativeSession(FullJid recipient, String sessionId, String altSessionId) - throws InterruptedException, XMPPException.XMPPErrorException, - SmackException.NotConnectedException, SmackException.NoResponseException { - - Jingle jingle = createSessionTerminateAlternativeSession(recipient, sessionId, altSessionId); - return connection.createStanzaCollectorAndSend(jingle).nextResultOrThrow(); - } - - public Jingle createSessionTerminateCancel(FullJid recipient, String sessionId) { - return createSessionTerminate(recipient, sessionId, JingleReason.Reason.cancel); - } - - public IQ sendSessionTerminateCancel(FullJid recipient, - String sessionId) - throws InterruptedException, XMPPException.XMPPErrorException, - SmackException.NotConnectedException, SmackException.NoResponseException { - - Jingle jingle = createSessionTerminateCancel(recipient, sessionId); - return connection.createStanzaCollectorAndSend(jingle).nextResultOrThrow(); - } - - public Jingle createSessionTerminateContentCancel(FullJid recipient, String sessionId, - JingleContent.Creator contentCreator, String contentName) { - Jingle.Builder jb = Jingle.getBuilder(); - jb.setAction(JingleAction.session_terminate) - .setSessionId(sessionId); - - JingleContent.Builder cb = JingleContent.getBuilder(); - cb.setCreator(contentCreator).setName(contentName); - - Jingle jingle = jb.addJingleContent(cb.build()).build(); - jingle.setFrom(connection.getUser()); - jingle.setTo(recipient); - - return jingle; - } - - public IQ sendSessionTerminateContentCancel(FullJid recipient, String sessionId, - JingleContent.Creator contentCreator, String contentName) - throws SmackException.NotConnectedException, InterruptedException, - XMPPException.XMPPErrorException, SmackException.NoResponseException { - Jingle jingle = createSessionTerminateContentCancel(recipient, sessionId, contentCreator, contentName); - return connection.createStanzaCollectorAndSend(jingle).nextResultOrThrow(); - } - - public Jingle createSessionTerminateUnsupportedTransports(FullJid recipient, String sessionId) { - return createSessionTerminate(recipient, sessionId, JingleReason.Reason.unsupported_transports); - } - - public IQ sendSessionTerminateUnsupportedTransports(FullJid recipient, String sessionId) - throws InterruptedException, XMPPException.XMPPErrorException, - SmackException.NotConnectedException, SmackException.NoResponseException { - Jingle jingle = createSessionTerminateUnsupportedTransports(recipient, sessionId); - return connection.createStanzaCollectorAndSend(jingle).nextResultOrThrow(); - } - - public Jingle createSessionTerminateFailedTransport(FullJid recipient, String sessionId) { - return createSessionTerminate(recipient, sessionId, JingleReason.Reason.failed_transport); - } - - public IQ sendSessionTerminateFailedTransport(FullJid recipient, String sessionId) - throws InterruptedException, XMPPException.XMPPErrorException, - SmackException.NotConnectedException, SmackException.NoResponseException { - Jingle jingle = createSessionTerminateFailedTransport(recipient, sessionId); - return connection.createStanzaCollectorAndSend(jingle).nextResultOrThrow(); - } - - public Jingle createSessionTerminateUnsupportedApplications(FullJid recipient, String sessionId) { - return createSessionTerminate(recipient, sessionId, JingleReason.Reason.unsupported_applications); - } - - public IQ sendSessionTerminateUnsupportedApplications(FullJid recipient, String sessionId) - throws InterruptedException, XMPPException.XMPPErrorException, - SmackException.NotConnectedException, SmackException.NoResponseException { - Jingle jingle = createSessionTerminateUnsupportedApplications(recipient, sessionId); - return connection.createStanzaCollectorAndSend(jingle).nextResultOrThrow(); - } - - public Jingle createSessionTerminateFailedApplication(FullJid recipient, String sessionId) { - return createSessionTerminate(recipient, sessionId, JingleReason.Reason.failed_application); - } - - public IQ sendSessionTerminateFailedApplication(FullJid recipient, String sessionId) - throws InterruptedException, XMPPException.XMPPErrorException, - SmackException.NotConnectedException, SmackException.NoResponseException { - Jingle jingle = createSessionTerminateFailedApplication(recipient, sessionId); - return connection.createStanzaCollectorAndSend(jingle).nextResultOrThrow(); - } - - public Jingle createSessionTerminateIncompatibleParameters(FullJid recipient, String sessionId) { - return createSessionTerminate(recipient, sessionId, JingleReason.Reason.incompatible_parameters); - } - - public IQ sendSessionTerminateIncompatibleParameters(FullJid recipient, String sessionId) - throws InterruptedException, XMPPException.XMPPErrorException, - SmackException.NotConnectedException, SmackException.NoResponseException { - Jingle jingle = createSessionTerminateIncompatibleParameters(recipient, sessionId); - return connection.createStanzaCollectorAndSend(jingle).nextResultOrThrow(); - } - - public IQ sendContentRejectFileNotAvailable(FullJid recipient, String sessionId, JingleContentDescription description) { - return null; //TODO Later - } - - public Jingle createSessionPing(FullJid recipient, String sessionId) { - Jingle.Builder jb = Jingle.getBuilder(); - jb.setSessionId(sessionId) - .setAction(JingleAction.session_info); - - Jingle jingle = jb.build(); - jingle.setFrom(connection.getUser()); - jingle.setTo(recipient); - - return jingle; - } - - public IQ sendSessionPing(FullJid recipient, String sessionId) - throws SmackException.NotConnectedException, InterruptedException, - XMPPException.XMPPErrorException, SmackException.NoResponseException { - Jingle jingle = createSessionPing(recipient, sessionId); - return connection.createStanzaCollectorAndSend(jingle).nextResultOrThrow(); - } - - public IQ createAck(Jingle jingle) { - return IQ.createResultIQ(jingle); - } - - public void sendAck(Jingle jingle) throws SmackException.NotConnectedException, InterruptedException { - connection.sendStanza(createAck(jingle)); - } - - public Jingle createTransportReplace(FullJid recipient, FullJid initiator, String sessionId, - JingleContent.Creator contentCreator, String contentName, - JingleContentTransport transport) { - Jingle.Builder jb = Jingle.getBuilder(); - jb.setInitiator(initiator) - .setSessionId(sessionId) - .setAction(JingleAction.transport_replace); - - JingleContent.Builder cb = JingleContent.getBuilder(); - cb.setName(contentName).setCreator(contentCreator).setTransport(transport); - Jingle jingle = jb.addJingleContent(cb.build()).build(); - - jingle.setTo(recipient); - jingle.setFrom(connection.getUser()); - - return jingle; - } - - public IQ sendTransportReplace(FullJid recipient, FullJid initiator, String sessionId, - JingleContent.Creator contentCreator, String contentName, - JingleContentTransport transport) - throws SmackException.NotConnectedException, InterruptedException, - XMPPException.XMPPErrorException, SmackException.NoResponseException { - Jingle jingle = createTransportReplace(recipient, initiator, sessionId, contentCreator, contentName, transport); - return connection.createStanzaCollectorAndSend(jingle).nextResultOrThrow(); - } - - public Jingle createTransportAccept(FullJid recipient, FullJid initiator, String sessionId, - JingleContent.Creator contentCreator, String contentName, - JingleContentTransport transport) { - Jingle.Builder jb = Jingle.getBuilder(); - jb.setAction(JingleAction.transport_accept) - .setInitiator(initiator) - .setSessionId(sessionId); - - JingleContent.Builder cb = JingleContent.getBuilder(); - cb.setCreator(contentCreator).setName(contentName).setTransport(transport); - - Jingle jingle = jb.addJingleContent(cb.build()).build(); - jingle.setTo(recipient); - jingle.setFrom(connection.getUser()); - - return jingle; - } - - public IQ sendTransportAccept(FullJid recipient, FullJid initiator, String sessionId, - JingleContent.Creator contentCreator, String contentName, - JingleContentTransport transport) - throws SmackException.NotConnectedException, InterruptedException, - XMPPException.XMPPErrorException, SmackException.NoResponseException { - Jingle jingle = createTransportAccept(recipient, initiator, sessionId, contentCreator, contentName, transport); - return connection.createStanzaCollectorAndSend(jingle).nextResultOrThrow(); - } - - public Jingle createTransportReject(FullJid recipient, FullJid initiator, String sessionId, - JingleContent.Creator contentCreator, String contentName, - JingleContentTransport transport) { - Jingle.Builder jb = Jingle.getBuilder(); - jb.setAction(JingleAction.transport_reject) - .setInitiator(initiator) - .setSessionId(sessionId); - - JingleContent.Builder cb = JingleContent.getBuilder(); - cb.setCreator(contentCreator).setName(contentName).setTransport(transport); - - Jingle jingle = jb.addJingleContent(cb.build()).build(); - jingle.setTo(recipient); - jingle.setFrom(connection.getUser()); - - return jingle; - } - - public IQ sendTransportReject(FullJid recipient, FullJid initiator, String sessionId, - JingleContent.Creator contentCreator, String contentName, - JingleContentTransport transport) - throws SmackException.NotConnectedException, InterruptedException, - XMPPException.XMPPErrorException, SmackException.NoResponseException { - Jingle jingle = createTransportReject(recipient, initiator, sessionId, contentCreator, contentName, transport); - return connection.createStanzaCollectorAndSend(jingle).nextResultOrThrow(); - } - - /* - * #################################################################################################### - */ - - public IQ createErrorUnknownSession(Jingle request) { - XMPPError.Builder error = XMPPError.getBuilder(); - error.setCondition(XMPPError.Condition.item_not_found) - .addExtension(JingleError.UNKNOWN_SESSION); - return IQ.createErrorResponse(request, error); - } - - public void sendErrorUnknownSession(Jingle request) - throws SmackException.NotConnectedException, InterruptedException { - connection.sendStanza(createErrorUnknownSession(request)); - } - - public IQ createErrorUnknownInitiator(Jingle request) { - return IQ.createErrorResponse(request, XMPPError.Condition.service_unavailable); - } - - public void sendErrorUnknownInitiator(Jingle request) - throws SmackException.NotConnectedException, InterruptedException { - connection.sendStanza(createErrorUnknownInitiator(request)); - } - - public IQ createErrorUnsupportedInfo(Jingle request) { - XMPPError.Builder error = XMPPError.getBuilder(); - error.setCondition(XMPPError.Condition.feature_not_implemented) - .addExtension(JingleError.UNSUPPORTED_INFO); - return IQ.createErrorResponse(request, error); - } - - public void sendErrorUnsupportedInfo(Jingle request) - throws SmackException.NotConnectedException, InterruptedException { - connection.sendStanza(createErrorUnsupportedInfo(request)); - } - - public IQ createErrorTieBreak(Jingle request) { - XMPPError.Builder error = XMPPError.getBuilder(); - error.setCondition(XMPPError.Condition.conflict) - .addExtension(JingleError.TIE_BREAK); - return IQ.createErrorResponse(request, error); - } - - public void sendErrorTieBreak(Jingle request) - throws SmackException.NotConnectedException, InterruptedException { - connection.sendStanza(createErrorTieBreak(request)); - } - - public IQ createErrorOutOfOrder(Jingle request) { - XMPPError.Builder error = XMPPError.getBuilder(); - error.setCondition(XMPPError.Condition.unexpected_request) - .addExtension(JingleError.OUT_OF_ORDER); - return IQ.createErrorResponse(request, error); - } - - public void sendErrorOutOfOrder(Jingle request) - throws SmackException.NotConnectedException, InterruptedException { - connection.sendStanza(createErrorOutOfOrder(request)); - } - - public IQ createErrorMalformedRequest(Jingle request) { - return IQ.createErrorResponse(request, XMPPError.Condition.bad_request); - } - - public void sendErrorMalformedRequest(Jingle request) - throws SmackException.NotConnectedException, InterruptedException { - connection.sendStanza(createErrorMalformedRequest(request)); - } -} 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 new file mode 100644 index 000000000..5d9aa4bdd --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/adapter/JingleDescriptionAdapter.java @@ -0,0 +1,32 @@ +/** + * + * 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.adapter; + +import org.jivesoftware.smackx.jingle.component.JingleDescription; +import org.jivesoftware.smackx.jingle.element.JingleContentDescriptionElement; +import org.jivesoftware.smackx.jingle.element.JingleContentElement; + +/** + * Adapter that creates a Description object from an element. + */ +public interface JingleDescriptionAdapter> { + + D descriptionFromElement(JingleContentElement.Creator creator, JingleContentElement.Senders senders, + String contentName, String contentDisposition, JingleContentDescriptionElement element); + + String getNamespace(); +} 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 new file mode 100644 index 000000000..683049919 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/adapter/JingleSecurityAdapter.java @@ -0,0 +1,30 @@ +/** + * + * 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.adapter; + +import org.jivesoftware.smackx.jingle.component.JingleSecurity; +import org.jivesoftware.smackx.jingle.element.JingleContentSecurityElement; + +/** + * Adapter that creates a Security object from an element. + */ +public interface JingleSecurityAdapter> { + + S securityFromElement(JingleContentSecurityElement element); + + String getNamespace(); +} 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 new file mode 100644 index 000000000..4a550ceea --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/adapter/JingleTransportAdapter.java @@ -0,0 +1,30 @@ +/** + * + * 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.adapter; + +import org.jivesoftware.smackx.jingle.component.JingleTransport; +import org.jivesoftware.smackx.jingle.element.JingleContentTransportElement; + +/** + * Adapter that creates a Transport element from an element. + */ +public interface JingleTransportAdapter> { + + T transportFromElement(JingleContentTransportElement element); + + String getNamespace(); +} 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 new file mode 100644 index 000000000..672be8d4c --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/adapter/package-info.java @@ -0,0 +1,22 @@ +/** + * + * Copyright 2017 Florian Schmaus, 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. + */ + +/** + * Smack's API for XEP-0166: Jingle. + * Adapters. + */ +package org.jivesoftware.smackx.jingle.adapter; diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/JingleTransportInitiationCallback.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/callbacks/JingleSecurityCallback.java similarity index 71% rename from smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/JingleTransportInitiationCallback.java rename to smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/callbacks/JingleSecurityCallback.java index 79932c1e0..afcd9d141 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/JingleTransportInitiationCallback.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/callbacks/JingleSecurityCallback.java @@ -14,17 +14,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jivesoftware.smackx.jingle.transports; +package org.jivesoftware.smackx.jingle.callbacks; import org.jivesoftware.smackx.bytestreams.BytestreamSession; /** - * Callback for bytestream session creation of TransportManagers. + * Callback used to signal success/failure of Jingle Security components. */ -public interface JingleTransportInitiationCallback { +public interface JingleSecurityCallback { - void onSessionInitiated(BytestreamSession bytestreamSession); - - void onException(Exception e); + void onSecurityReady(BytestreamSession bytestreamSession); + void onSecurityFailed(Exception e); } 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/callbacks/JingleTransportCallback.java new file mode 100644 index 000000000..2cb3405e9 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/callbacks/JingleTransportCallback.java @@ -0,0 +1,29 @@ +/** + * + * 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.callbacks; + +import org.jivesoftware.smackx.bytestreams.BytestreamSession; + +/** + * Created by vanitas on 27.07.17. + */ +public interface JingleTransportCallback { + + void onTransportReady(BytestreamSession bytestreamSession); + + 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/callbacks/package-info.java new file mode 100644 index 000000000..d51d7d3d2 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/callbacks/package-info.java @@ -0,0 +1,22 @@ +/** + * + * Copyright 2017 Florian Schmaus, 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. + */ + +/** + * Smack's API for XEP-0166: Jingle. + * Callbacks. + */ +package org.jivesoftware.smackx.jingle.callbacks; 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 new file mode 100644 index 000000000..71b16a61a --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/component/JingleContent.java @@ -0,0 +1,492 @@ +/** + * + * 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.component; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import java.util.logging.Level; +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.smack.packet.XMPPError; +import org.jivesoftware.smack.util.Async; +import org.jivesoftware.smack.util.StringUtils; +import org.jivesoftware.smackx.bytestreams.BytestreamSession; +import org.jivesoftware.smackx.jingle.JingleManager; +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.element.JingleContentDescriptionElement; +import org.jivesoftware.smackx.jingle.element.JingleContentElement; +import org.jivesoftware.smackx.jingle.element.JingleContentSecurityElement; +import org.jivesoftware.smackx.jingle.element.JingleContentTransportElement; +import org.jivesoftware.smackx.jingle.element.JingleElement; +import org.jivesoftware.smackx.jingle.element.JingleReasonElement; + +/** + * Internal class that holds the state of a content in a modifiable form. + */ +public class JingleContent implements JingleTransportCallback, JingleSecurityCallback { + + private static final Logger LOGGER = Logger.getLogger(JingleContent.class.getName()); + + private final JingleContentElement.Creator creator; + private final String name; + private final String disposition; + private JingleSession parent; + private JingleContentElement.Senders senders; + private JingleDescription description; + private JingleTransport transport; + private JingleSecurity security; + + private JingleTransport pendingReplacingTransport = null; + + private final Set transportBlacklist = Collections.synchronizedSet(new HashSet()); + + public JingleContent(JingleContentElement.Creator creator, JingleContentElement.Senders senders) { + this(null, null, null, randomName(), null, creator, senders); + } + + public JingleContent(JingleDescription description, JingleTransport transport, JingleSecurity security, String name, String disposition, JingleContentElement.Creator creator, JingleContentElement.Senders senders) { + setDescription(description); + setTransport(transport); + setSecurity(security); + this.name = name; + this.disposition = disposition; + this.creator = creator; + this.senders = senders; + } + + public static JingleContent fromElement(JingleContentElement content) { + JingleDescription description = null; + JingleTransport transport = null; + JingleSecurity security = null; + + JingleContentDescriptionElement descriptionElement = content.getDescription(); + if (descriptionElement != null) { + JingleDescriptionAdapter descriptionAdapter = JingleManager.getJingleDescriptionAdapter(content.getDescription().getNamespace()); + if (descriptionAdapter != null) { + description = descriptionAdapter.descriptionFromElement(content.getCreator(), content.getSenders(), content.getName(), content.getDisposition(), descriptionElement); + } else { + throw new AssertionError("Unsupported Description: " + descriptionElement.getNamespace()); + } + } + + JingleContentTransportElement transportElement = content.getTransport(); + if (transportElement != null) { + JingleTransportAdapter transportAdapter = JingleManager.getJingleTransportAdapter(content.getTransport().getNamespace()); + if (transportAdapter != null) { + transport = transportAdapter.transportFromElement(transportElement); + } else { + throw new AssertionError("Unsupported Transport: " + transportElement.getNamespace()); + } + } + + JingleContentSecurityElement securityElement = content.getSecurity(); + if (securityElement != null) { + JingleSecurityAdapter securityAdapter = JingleManager.getJingleSecurityAdapter(content.getSecurity().getNamespace()); + if (securityAdapter != null) { + security = securityAdapter.securityFromElement(securityElement); + } else { + throw new AssertionError("Unsupported Security: " + securityElement.getNamespace()); + } + } + + return new JingleContent(description, transport, security, content.getName(), content.getDisposition(), content.getCreator(), content.getSenders()); + } + + public void setSenders(JingleContentElement.Senders senders) { + this.senders = senders; + } + + /* HANDLE_XYZ */ + + public IQ handleJingleRequest(JingleElement request, XMPPConnection connection) { + switch (request.getAction()) { + case content_modify: + return handleContentModify(request, connection); + case description_info: + return handleDescriptionInfo(request, connection); + case security_info: + return handleSecurityInfo(request, connection); + case session_info: + return handleSessionInfo(request, connection); + case transport_accept: + return handleTransportAccept(request, connection); + case transport_info: + return handleTransportInfo(request, connection); + case transport_reject: + return handleTransportReject(request, connection); + case transport_replace: + return handleTransportReplace(request, connection); + default: + throw new AssertionError("Illegal jingle action: " + request.getAction() + " is not allowed here."); + } + } + + void handleContentAccept(JingleElement request, XMPPConnection connection) { + start(connection); + } + + + IQ handleSessionAccept(JingleElement request, XMPPConnection connection) { + LOGGER.log(Level.INFO, "RECEIVED SESSION ACCEPT!"); + JingleContentElement contentElement = null; + for (JingleContentElement c : request.getContents()) { + if (c.getName().equals(getName())) { + contentElement = c; + break; + } + } + + if (contentElement == null) { + throw new AssertionError("Session Accept did not contain this content."); + } + + getTransport().handleSessionAccept(contentElement.getTransport(), connection); + start(connection); + return IQ.createResultIQ(request); + } + + private IQ handleContentModify(JingleElement request, XMPPConnection connection) { + return IQ.createErrorResponse(request, XMPPError.Condition.feature_not_implemented); + } + + private IQ handleDescriptionInfo(JingleElement request, XMPPConnection connection) { + return IQ.createErrorResponse(request, XMPPError.Condition.feature_not_implemented); + } + + public void handleContentRemove(JingleSession session, XMPPConnection connection) { + } + + private IQ handleSecurityInfo(JingleElement request, XMPPConnection connection) { + return IQ.createErrorResponse(request, XMPPError.Condition.feature_not_implemented); + } + + private IQ handleSessionInfo(JingleElement request, XMPPConnection connection) { + return IQ.createResultIQ(request); + } + + private IQ handleTransportAccept(JingleElement request, XMPPConnection connection) { + + if (pendingReplacingTransport == null) { + LOGGER.log(Level.WARNING, "Received transport-accept, but apparently we did not try to replace the transport."); + return JingleElement.createJingleErrorOutOfOrder(request); + } + + transport = pendingReplacingTransport; + pendingReplacingTransport = null; + + start(connection); + + return IQ.createResultIQ(request); + } + + private IQ handleTransportInfo(JingleElement request, XMPPConnection connection) { + assert request.getContents().size() == 1; + JingleContentElement content = request.getContents().get(0); + + return transport.handleTransportInfo(content.getTransport().getInfo(), request); + } + + private IQ handleTransportReject(JingleElement request, XMPPConnection connection) { + if (pendingReplacingTransport == null) { + throw new AssertionError("We didn't try to replace the transport."); + } + transportBlacklist.add(pendingReplacingTransport.getNamespace()); + pendingReplacingTransport = null; + try { + replaceTransport(transportBlacklist, connection); + } catch (SmackException.NotConnectedException | SmackException.NoResponseException | XMPPException.XMPPErrorException | InterruptedException e) { + LOGGER.log(Level.SEVERE, "Could not replace transport: " + e, e); + } + return IQ.createResultIQ(request); + } + + private IQ handleTransportReplace(final JingleElement request, final XMPPConnection connection) { + //Tie Break? + if (pendingReplacingTransport != null) { + Async.go(new Runnable() { + @Override + public void run() { + try { + connection.createStanzaCollectorAndSend(JingleElement.createJingleErrorTieBreak(request)).nextResultOrThrow(); + } catch (SmackException.NoResponseException | SmackException.NotConnectedException | InterruptedException | XMPPException.XMPPErrorException e) { + LOGGER.log(Level.SEVERE, "Could not send tie-break: " + e, e); + } + } + }); + return IQ.createResultIQ(request); + } + + JingleContentElement contentElement = null; + for (JingleContentElement c : request.getContents()) { + if (c.getName().equals(getName())) { + contentElement = c; + break; + } + } + + if (contentElement == null) { + throw new AssertionError("Unknown content"); + } + + final JingleSession session = getParent(); + final JingleContentTransportElement transportElement = contentElement.getTransport(); + + JingleTransportManager tm = session.getJingleManager().getTransportManager(transportElement.getNamespace()); + + // Unsupported/Blacklisted transport -> reject. + if (tm == null || getTransportBlacklist().contains(transportElement.getNamespace())) { + Async.go(new Runnable() { + @Override + public void run() { + try { + getParent().getJingleManager().getConnection().createStanzaCollectorAndSend(JingleElement.createTransportReject(session.getOurJid(), session.getPeer(), session.getSessionId(), getCreator(), getName(), transportElement)); + } catch (SmackException.NotConnectedException | InterruptedException e) { + LOGGER.log(Level.SEVERE, "Could not send transport-reject: " + e, e); + } + } + }); + + } else { + //Blacklist current transport + this.getTransportBlacklist().add(this.transport.getNamespace()); + + this.transport = tm.createTransportForResponder(this, transportElement); + Async.go(new Runnable() { + @Override + public void run() { + try { + getParent().getJingleManager().getConnection().createStanzaCollectorAndSend(JingleElement.createTransportAccept(session.getOurJid(), session.getPeer(), session.getSessionId(), getCreator(), getName(), transport.getElement())); + } catch (SmackException.NotConnectedException | InterruptedException e) { + LOGGER.log(Level.SEVERE, "Could not send transport-accept: " + e, e); + } + } + }); + start(connection); + } + + return IQ.createResultIQ(request); + } + + /* MISCELLANEOUS */ + + public JingleContentElement getElement() { + JingleContentElement.Builder builder = JingleContentElement.getBuilder() + .setName(name) + .setCreator(creator) + .setSenders(senders) + .setDisposition(disposition); + + if (description != null) { + builder.setDescription(description.getElement()); + } + + if (transport != null) { + builder.setTransport(transport.getElement()); + } + + if (security != null) { + builder.setSecurity(security.getElement()); + } + + return builder.build(); + } + + public Set getTransportBlacklist() { + return transportBlacklist; + } + + public JingleContentElement.Creator getCreator() { + return creator; + } + + public String getName() { + return name; + } + + public JingleContentElement.Senders getSenders() { + return senders; + } + + public void setParent(JingleSession session) { + if (this.parent != session) { + this.parent = session; + } + } + + public JingleSession getParent() { + return parent; + } + + public JingleDescription getDescription() { + return description; + } + + public void setDescription(JingleDescription description) { + if (description != null && this.description != description) { + this.description = description; + description.setParent(this); + } + } + + public JingleTransport getTransport() { + return transport; + } + + public void setTransport(JingleTransport transport) { + if (transport != null && this.transport != transport) { + this.transport = transport; + transport.setParent(this); + } + } + + public JingleSecurity getSecurity() { + return security; + } + + public void setSecurity(JingleSecurity security) { + if (security != null && this.security != security) { + this.security = security; + security.setParent(this); + } + } + + public boolean isSending() { + return (getSenders() == JingleContentElement.Senders.initiator && getParent().isInitiator()) || + (getSenders() == JingleContentElement.Senders.responder && getParent().isResponder()) || + getSenders() == JingleContentElement.Senders.both; + } + + public boolean isReceiving() { + return (getSenders() == JingleContentElement.Senders.initiator && getParent().isResponder()) || + (getSenders() == JingleContentElement.Senders.responder && getParent().isInitiator()) || + getSenders() == JingleContentElement.Senders.both; + } + + public void start(final XMPPConnection connection) { + transport.prepare(connection); + + if (security != null) { + security.prepare(connection, getParent().getPeer()); + } + + //Establish transport + Async.go(new Runnable() { + @Override + public void run() { + try { + if (isReceiving()) { + LOGGER.log(Level.INFO, "Establish incoming bytestream."); + getTransport().establishIncomingBytestreamSession(connection, JingleContent.this, getParent()); + } else if (isSending()) { + LOGGER.log(Level.INFO, "Establish outgoing bytestream."); + getTransport().establishOutgoingBytestreamSession(connection, JingleContent.this, getParent()); + } else { + LOGGER.log(Level.INFO, "Neither receiving, nor sending. Assume receiving."); + getTransport().establishIncomingBytestreamSession(connection, JingleContent.this, getParent()); + } + } catch (SmackException.NotConnectedException | InterruptedException e) { + LOGGER.log(Level.SEVERE, "Error establishing connection: " + e, e); + } + } + }); + } + + @Override + public void onTransportReady(BytestreamSession bytestreamSession) { + LOGGER.log(Level.INFO, "TransportReady: " + (isReceiving() ? "Receive" : "Send")); + if (bytestreamSession == null) { + throw new AssertionError("bytestreamSession MUST NOT be null at this point."); + } + + if (security != null) { + if (isReceiving()) { + LOGGER.log(Level.INFO, "Decrypt incoming Bytestream."); + getSecurity().decryptIncomingBytestream(bytestreamSession, this); + } else if (isSending()) { + LOGGER.log(Level.INFO, "Encrypt outgoing Bytestream."); + getSecurity().encryptOutgoingBytestream(bytestreamSession, this); + } + } else { + description.onBytestreamReady(bytestreamSession); + } + } + + @Override + public void onTransportFailed(Exception e) { + //Add current transport to blacklist. + getTransportBlacklist().add(transport.getNamespace()); + + //Replace transport. + if (getParent().isInitiator()) { + try { + replaceTransport(getTransportBlacklist(), getParent().getJingleManager().getConnection()); + } catch (SmackException.NotConnectedException | InterruptedException | SmackException.NoResponseException | XMPPException.XMPPErrorException e1) { + LOGGER.log(Level.SEVERE, "Could not send transport-replace: " + e, e); + } + } + } + + @Override + public void onSecurityReady(BytestreamSession bytestreamSession) { + getDescription().onBytestreamReady(bytestreamSession); + } + + @Override + public void onSecurityFailed(Exception e) { + LOGGER.log(Level.SEVERE, "Security failed: " + e, e); + } + + private void replaceTransport(Set blacklist, XMPPConnection connection) + throws SmackException.NotConnectedException, InterruptedException, + XMPPException.XMPPErrorException, SmackException.NoResponseException { + if (pendingReplacingTransport != null) { + throw new AssertionError("Transport replace already pending."); + } + + JingleSession session = getParent(); + JingleManager jingleManager = session.getJingleManager(); + + JingleTransportManager rManager = jingleManager.getBestAvailableTransportManager(getParent().getPeer(), blacklist); + if (rManager == null) { + JingleElement failedTransport = JingleElement.createSessionTerminate(session.getPeer(), + session.getSessionId(), JingleReasonElement.Reason.failed_transport); + connection.createStanzaCollectorAndSend(failedTransport).nextResultOrThrow(); + return; + } + + pendingReplacingTransport = rManager.createTransportForInitiator(this); + + JingleElement transportReplace = JingleElement.createTransportReplace(session.getInitiator(), session.getPeer(), + session.getSessionId(), getCreator(), getName(), pendingReplacingTransport.getElement()); + + connection.createStanzaCollectorAndSend(transportReplace).nextResultOrThrow(); + } + + 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 new file mode 100644 index 000000000..5c6646c39 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/component/JingleDescription.java @@ -0,0 +1,48 @@ +/** + * + * 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.component; + +import org.jivesoftware.smackx.bytestreams.BytestreamSession; +import org.jivesoftware.smackx.jingle.element.JingleContentDescriptionElement; +import org.jivesoftware.smackx.jingle.element.JingleContentDescriptionInfoElement; +import org.jivesoftware.smackx.jingle.element.JingleElement; + +/** + * Class that represents a contents description component. + */ +public abstract class JingleDescription { + + private JingleContent parent; + + public abstract D getElement(); + + public void setParent(JingleContent parent) { + if (this.parent != parent) { + this.parent = parent; + } + } + + public abstract JingleElement handleDescriptionInfo(JingleContentDescriptionInfoElement info); + + public JingleContent getParent() { + return parent; + } + + public abstract void onBytestreamReady(BytestreamSession bytestreamSession); + + public abstract String getNamespace(); +} 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 new file mode 100644 index 000000000..762e4d271 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/component/JingleSecurity.java @@ -0,0 +1,56 @@ +/** + * + * 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.component; + +import org.jivesoftware.smack.XMPPConnection; +import org.jivesoftware.smackx.bytestreams.BytestreamSession; +import org.jivesoftware.smackx.jingle.callbacks.JingleSecurityCallback; +import org.jivesoftware.smackx.jingle.element.JingleContentSecurityElement; +import org.jivesoftware.smackx.jingle.element.JingleContentSecurityInfoElement; +import org.jivesoftware.smackx.jingle.element.JingleElement; + +import org.jxmpp.jid.FullJid; + +/** + * Class that represents a contents security component. + */ +public abstract class JingleSecurity { + + private JingleContent parent; + + public abstract D getElement(); + + public abstract JingleElement handleSecurityInfo(JingleContentSecurityInfoElement element, JingleElement wrapping); + + public void setParent(JingleContent parent) { + if (this.parent != parent) { + this.parent = parent; + } + } + + public JingleContent getParent() { + return parent; + } + + public abstract void decryptIncomingBytestream(BytestreamSession bytestreamSession, JingleSecurityCallback callback); + + public abstract void encryptOutgoingBytestream(BytestreamSession bytestreamSession, JingleSecurityCallback callbacks); + + public abstract String getNamespace(); + + public abstract void prepare(XMPPConnection connection, FullJid sender); +} 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 new file mode 100644 index 000000000..0988dd07b --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/component/JingleSecurityBytestreamSession.java @@ -0,0 +1,43 @@ +/** + * + * 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.component; + +import java.io.IOException; + +import org.jivesoftware.smackx.bytestreams.BytestreamSession; + +/** + * Created by vanitas on 27.07.17. + */ +public abstract class JingleSecurityBytestreamSession implements BytestreamSession { + + protected BytestreamSession wrapped; + + @Override + public int getReadTimeout() throws IOException { + return wrapped.getReadTimeout(); + } + + @Override + 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 new file mode 100644 index 000000000..33abe2f12 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/component/JingleSession.java @@ -0,0 +1,424 @@ +/** + * + * 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.component; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Level; +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.smack.packet.XMPPError; +import org.jivesoftware.smack.util.Async; +import org.jivesoftware.smackx.jingle.JingleDescriptionManager; +import org.jivesoftware.smackx.jingle.JingleManager; +import org.jivesoftware.smackx.jingle.element.JingleAction; +import org.jivesoftware.smackx.jingle.element.JingleContentElement; +import org.jivesoftware.smackx.jingle.element.JingleElement; +import org.jivesoftware.smackx.jingle.element.JingleReasonElement; +import org.jivesoftware.smackx.jingle.exception.UnsupportedDescriptionException; +import org.jivesoftware.smackx.jingle.exception.UnsupportedSecurityException; +import org.jivesoftware.smackx.jingle.exception.UnsupportedTransportException; +import org.jivesoftware.smackx.jingle.util.Role; + +import org.jxmpp.jid.FullJid; + +/** + * Class that represents a Jingle session. + */ +public class JingleSession { + private static final Logger LOGGER = Logger.getLogger(JingleSession.class.getName()); + + private final ConcurrentHashMap contents = new ConcurrentHashMap<>(); + private final ConcurrentHashMap proposedContents = new ConcurrentHashMap<>(); + private final JingleManager jingleManager; + + private final FullJid initiator, responder; + private final Role role; + private final String sessionId; + + public enum SessionState { + fresh, //pre-session-inititate + pending, //pre-session-accept + active, //pre-session-terminate + ended //post-session-terminate + } + + private SessionState sessionState; + + public JingleSession(JingleManager manager, FullJid initiator, FullJid responder, Role role, String sessionId) { + this.jingleManager = manager; + this.initiator = initiator; + this.responder = responder; + this.role = role; + this.sessionId = sessionId; + this.sessionState = SessionState.fresh; + } + + public static JingleSession fromSessionInitiate(JingleManager manager, JingleElement initiate) + throws UnsupportedSecurityException, UnsupportedDescriptionException, UnsupportedTransportException { + if (initiate.getAction() != JingleAction.session_initiate) { + throw new IllegalArgumentException("Jingle-Action MUST be 'session-initiate'."); + } + + JingleSession session = new JingleSession(manager, initiate.getInitiator(), manager.getConnection().getUser().asFullJidOrThrow(), Role.responder, initiate.getSid()); + List initiateContents = initiate.getContents(); + + for (JingleContentElement content : initiateContents) { + session.addContent(content, manager); + } + + session.sessionState = SessionState.pending; + + return session; + } + + 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."); + } + + connection.createStanzaCollectorAndSend(createSessionInitiate()).nextResultOrThrow(); + this.sessionState = SessionState.pending; + } + + 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 (contents.values().size() == 0) { + LOGGER.log(Level.WARNING, "0 contents!"); + } + + for (JingleContent content : contents.values()) { + content.start(connection); + } + + connection.createStanzaCollectorAndSend(createSessionAccept()).nextResultOrThrow(); + this.sessionState = SessionState.active; + } + + public JingleElement createSessionInitiate() { + if (role != Role.initiator) { + throw new IllegalStateException("Sessions role is not initiator."); + } + + List contentElements = new ArrayList<>(); + for (JingleContent c : contents.values()) { + contentElements.add(c.getElement()); + } + + return JingleElement.createSessionInitiate(getInitiator(), getResponder(), getSessionId(), contentElements); + } + + public JingleElement createSessionAccept() { + if (role != Role.responder) { + throw new IllegalStateException("Sessions role is not responder."); + } + + List contentElements = new ArrayList<>(); + for (JingleContent c : contents.values()) { + contentElements.add(c.getElement()); + } + + return JingleElement.createSessionAccept(getInitiator(), getResponder(), getSessionId(), contentElements); + } + + public IQ handleJingleRequest(JingleElement request) { + switch (request.getAction()) { + case content_modify: + case description_info: + case security_info: + case session_info: + case transport_accept: + case transport_info: + case transport_reject: + case transport_replace: + return getSoleAffectedContentOrThrow(request).handleJingleRequest(request, jingleManager.getConnection()); + case content_accept: + return handleContentAccept(request); + case content_add: + return handleContentAdd(request); + case content_reject: + return handleContentReject(request); + case content_remove: + return handleContentRemove(request); + case session_accept: + return handleSessionAccept(request); + case session_initiate: + return handleSessionInitiate(request); + case session_terminate: + return handleSessionTerminate(request); + default: + throw new AssertionError("Illegal jingle action: " + request.getAction()); + } + } + + /* ############## Processed in this class ############## */ + + /** + * Handle incoming session-accept stanza. + * @param request session-accept stanza. + * @return result. + */ + private IQ handleSessionAccept(final JingleElement request) { + this.sessionState = SessionState.active; + + for (final JingleContent content : contents.values()) { + Async.go(new Runnable() { + @Override + public void run() { + content.handleSessionAccept(request, jingleManager.getConnection()); + } + }); + } + + return IQ.createResultIQ(request); + } + + private IQ handleSessionInitiate(JingleElement request) { + JingleDescription description = getSoleContentOrThrow().getDescription(); + JingleDescriptionManager descriptionManager = jingleManager.getDescriptionManager(description.getNamespace()); + + if (descriptionManager == null) { + LOGGER.log(Level.WARNING, "Unsupported description type: " + description.getNamespace()); + return JingleElement.createSessionTerminate(getPeer(), getSessionId(), JingleReasonElement.Reason.unsupported_applications); + } + + descriptionManager.notifySessionInitiate(this); + + return IQ.createResultIQ(request); + } + + private IQ handleSessionTerminate(JingleElement request) { + this.sessionState = SessionState.ended; + JingleReasonElement reason = request.getReason(); + + if (reason == null) { + throw new AssertionError("Reason MUST not be null! (I guess)..."); + } + + //TODO: Inform client. + jingleManager.removeSession(this); + + return IQ.createResultIQ(request); + } + + 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!"); + } + + proposedContents.remove(accepted.getName()); + contents.put(accepted.getName(), accepted); + + Async.go(new Runnable() { + @Override + public void run() { + accepted.handleContentAccept(request, jingleManager.getConnection()); + } + }); + } + + return IQ.createResultIQ(request); + } + + private IQ handleContentAdd(JingleElement request) { + final JingleContent proposed = getSoleProposedContentOrThrow(request); + + final JingleDescriptionManager descriptionManager = jingleManager.getDescriptionManager(proposed.getDescription().getNamespace()); + + if (descriptionManager == null) { + throw new AssertionError("DescriptionManager is null: " + proposed.getDescription().getNamespace()); + } + + Async.go(new Runnable() { + @Override + public void run() { + descriptionManager.notifyContentAdd(JingleSession.this, proposed); + } + }); + + return IQ.createResultIQ(request); + } + + private IQ handleContentReject(JingleElement request) { + for (JingleContentElement r : request.getContents()) { + final JingleContent rejected = proposedContents.get(r.getName()); + + if (rejected == null) { + throw new AssertionError("Illegal content name!"); + } + + proposedContents.remove(rejected.getName()); + + /* + Async.go(new Runnable() { + @Override + public void run() { + rejected.handleContentReject(request, jingleManager.getConnection()); + } + }); + */ + } + + return IQ.createResultIQ(request); + } + + private IQ handleContentRemove(final JingleElement request) { + return IQ.createErrorResponse(request, XMPPError.Condition.feature_not_implemented); + /* + for (JingleContentElement r : request.getContents()) { + final JingleContent removed = contents.get(r.getName()); + + if (removed == null) { + throw new AssertionError("Illegal content name!"); + } + + contents.remove(removed.getName()); + + Async.go(new Runnable() { + @Override + public void run() { + removed.handleContentRemove(JingleSession.this, jingleManager.getConnection()); + } + }); + } + + return IQ.createResultIQ(request); + */ + } + + public FullJid getInitiator() { + return initiator; + } + + public FullJid getResponder() { + return responder; + } + + public FullJid getPeer() { + return role == Role.initiator ? responder : initiator; + } + + public FullJid getOurJid() { + return role == Role.initiator ? initiator : responder; + } + + public boolean isInitiator() { + return role == Role.initiator; + } + + public boolean isResponder() { + return role == Role.responder; + } + + public String getSessionId() { + return sessionId; + } + + public JingleManager getJingleManager() { + return jingleManager; + } + + private HashMap getAffectedContents(JingleElement request) { + HashMap map = new HashMap<>(); + for (JingleContentElement e : request.getContents()) { + JingleContent c = contents.get(e.getName()); + if (c == null) { + throw new AssertionError("Unknown content: " + e.getName()); + } + map.put(e, c); + } + return map; + } + + private JingleContent getSoleAffectedContentOrThrow(JingleElement request) { + if (request.getContents().size() != 1) { + throw new AssertionError("More/less than 1 content in request!"); + } + + JingleContent content = contents.get(request.getContents().get(0).getName()); + if (content == null) { + throw new AssertionError("Illegal content name!"); + } + + return content; + } + + private static JingleContent getSoleProposedContentOrThrow(JingleElement request) { + if (request.getContents().size() != 1) { + throw new AssertionError("More/less than 1 content in request!"); + } + + return JingleContent.fromElement(request.getContents().get(0)); + } + + public void addContent(JingleContent content) { + if (contents.get(content.getName()) != null) { + throw new IllegalArgumentException("Session already contains a content with the name " + content.getName()); + } + contents.put(content.getName(), content); + content.setParent(this); + } + + public void addContent(JingleContentElement content, JingleManager manager) + throws UnsupportedSecurityException, UnsupportedTransportException, UnsupportedDescriptionException { + addContent(JingleContent.fromElement(content)); + } + + public ConcurrentHashMap getContents() { + return contents; + } + + public JingleContent getContent(String name) { + return contents.get(name); + } + + /** + * Get the only jingle content if one exists, or null. This method will throw an + * {@link IllegalStateException} if there is more than one jingle content. + * + * @return a JingleContent instance or null. + * @throws IllegalStateException if there is more than one jingle content. + */ + public JingleContent getSoleContentOrThrow() { + if (contents.isEmpty()) { + return null; + } + + if (contents.size() > 1) { + throw new IllegalStateException(); + } + + return contents.values().iterator().next(); + } + + 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 new file mode 100644 index 000000000..914327581 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/component/JingleTransport.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.component; + +import java.util.ArrayList; +import java.util.List; + +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.element.JingleContentTransportElement; +import org.jivesoftware.smackx.jingle.element.JingleContentTransportInfoElement; +import org.jivesoftware.smackx.jingle.element.JingleElement; + +/** + * Class that represents a contents transport component. + */ +public abstract class JingleTransport { + + private JingleContent parent; + private final ArrayList> ourCandidates = new ArrayList<>(); + private final ArrayList> theirCandidates = new ArrayList<>(); + + protected BytestreamSession bytestreamSession; + + public abstract D getElement(); + + public void addOurCandidate(JingleTransportCandidate candidate) { +// Insert sorted by descending priority + int i; + // Find appropriate index + for (i = 0; i < ourCandidates.size(); i++) { + JingleTransportCandidate c = ourCandidates.get(i); + + if (c == candidate || c.equals(candidate)) { + c.setParent(this); // Candidate might equal, but not be same, so set parent just in case + return; + } + + if (c.getPriority() < candidate.getPriority()) { + break; + } + } + + ourCandidates.add(i, candidate); + candidate.setParent(this); + } + + public void addTheirCandidate(JingleTransportCandidate candidate) { + // Insert sorted by descending priority + int i; + // Find appropriate index + for (i = 0; i < theirCandidates.size(); i++) { + JingleTransportCandidate c = theirCandidates.get(i); + + if (c == candidate || c.equals(candidate)) { + c.setParent(this); // Candidate might equal, but not be same, so set parent just in case + return; + } + + if (c.getPriority() < candidate.getPriority()) { + break; + } + } + + theirCandidates.add(i, candidate); + candidate.setParent(this); + } + + public abstract void prepare(XMPPConnection connection); + + public List> getOurCandidates() { + return ourCandidates; + } + + public List> getTheirCandidates() { + return theirCandidates; + } + + public abstract String getNamespace(); + + public abstract void establishIncomingBytestreamSession(XMPPConnection connection, JingleTransportCallback callback, JingleSession session) + throws SmackException.NotConnectedException, InterruptedException; + + public abstract void establishOutgoingBytestreamSession(XMPPConnection connection, JingleTransportCallback callback, JingleSession session) + throws SmackException.NotConnectedException, InterruptedException; + + public abstract IQ handleTransportInfo(JingleContentTransportInfoElement info, JingleElement wrapping); + + public void setParent(JingleContent parent) { + this.parent = parent; + } + + public JingleContent getParent() { + return parent; + } + + public abstract void handleSessionAccept(JingleContentTransportElement transportElement, XMPPConnection connection); + + 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 new file mode 100644 index 000000000..7a6af1b29 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/component/JingleTransportCandidate.java @@ -0,0 +1,48 @@ +/** + * + * 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.component; + +import org.jivesoftware.smackx.jingle.element.JingleContentTransportCandidateElement; + +/** + * Class that represents a transports candidate component. + */ +public abstract class JingleTransportCandidate { + + private JingleTransport parent; + private int priority; + + public void setParent(JingleTransport transport) { + if (parent != transport) { + parent = transport; + } + } + + public JingleTransport getParent() { + return parent; + } + + public int getPriority() { + return priority; + } + + public void setPriority(int priority) { + this.priority = priority; + } + + public abstract E getElement(); +} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/element/package-info.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/component/package-info.java similarity index 72% rename from smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/element/package-info.java rename to smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/component/package-info.java index da2e22582..c7dc0690f 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/element/package-info.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/component/package-info.java @@ -1,6 +1,6 @@ /** * - * Copyright 2017 Paul Schaub + * Copyright 2017 Florian Schmaus, Paul Schaub * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ */ /** - * Smack's API for XEP-0234: Jingle File Transfer. - * Elements. + * Smack's API for XEP-0166: Jingle. + * Internal components. */ -package org.jivesoftware.smackx.jingle_filetransfer.element; +package org.jivesoftware.smackx.jingle.component; diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/Jingle.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/Jingle.java deleted file mode 100644 index 12c2e4d5e..000000000 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/Jingle.java +++ /dev/null @@ -1,235 +0,0 @@ -/** - * - * Copyright 2003-2007 Jive Software, 2014-2017 Florian Schmaus - * - * 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.element; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import org.jivesoftware.smack.packet.IQ; -import org.jivesoftware.smack.util.Objects; -import org.jivesoftware.smack.util.StringUtils; - -import org.jxmpp.jid.FullJid; - -/** - * The Jingle element. - * - * @author Florian Schmaus - */ -public final class Jingle extends IQ { - - public static final String NAMESPACE = "urn:xmpp:jingle:1"; - - public static final String ACTION_ATTRIBUTE_NAME = "action"; - - public static final String INITIATOR_ATTRIBUTE_NAME = "initiator"; - - public static final String RESPONDER_ATTRIBUTE_NAME = "responder"; - - public static final String SESSION_ID_ATTRIBUTE_NAME = "sid"; - - public static final String ELEMENT = "jingle"; - - /** - * The session ID related to this session. The session ID is a unique identifier generated by the initiator. This - * should match the XML Nmtoken production so that XML character escaping is not needed for characters such as &. - */ - private final String sessionId; - - /** - * The jingle action. This attribute is required. - */ - private final JingleAction action; - - private final FullJid initiator; - - private final FullJid responder; - - private final JingleReason reason; - - private final List contents; - - private Jingle(String sessionId, JingleAction action, FullJid initiator, FullJid responder, JingleReason reason, - List contents) { - super(ELEMENT, NAMESPACE); - this.sessionId = StringUtils.requireNotNullOrEmpty(sessionId, "Jingle session ID must not be null"); - this.action = Objects.requireNonNull(action, "Jingle action must not be null"); - this.initiator = initiator; - this.responder = responder; - this.reason = reason; - if (contents != null) { - this.contents = Collections.unmodifiableList(contents); - } - else { - this.contents = Collections.emptyList(); - } - setType(Type.set); - } - - /** - * Get the initiator. The initiator will be the full JID of the entity that has initiated the flow (which may be - * different to the "from" address in the IQ) - * - * @return the initiator - */ - public FullJid getInitiator() { - return initiator; - } - - /** - * Get the responder. The responder is the full JID of the entity that has replied to the initiation (which may be - * different to the "to" addresss in the IQ). - * - * @return the responder - */ - public FullJid getResponder() { - return responder; - } - - /** - * Returns the session ID related to the session. The session ID is a unique identifier generated by the initiator. - * This should match the XML Nmtoken production so that XML character escaping is not needed for characters such as - * &. - * - * @return Returns the session ID related to the session. - */ - public String getSid() { - return sessionId; - } - - /** - * Get the action specified in the jingle IQ. - * - * @return the action. - */ - public JingleAction getAction() { - return action; - } - - public JingleReason getReason() { - return reason; - } - - /** - * Get a List of the contents. - * - * @return the contents. - */ - public List getContents() { - return contents; - } - - /** - * Get the only jingle content if one exists, or null. This method will throw an - * {@link IllegalStateException} if there is more than one jingle content. - * - * @return a JingleContent instance or null. - * @throws IllegalStateException if there is more than one jingle content. - */ - public JingleContent getSoleContentOrThrow() { - if (contents.isEmpty()) { - return null; - } - - if (contents.size() > 1) { - throw new IllegalStateException(); - } - - return contents.get(0); - } - - @Override - protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml) { - xml.optAttribute(INITIATOR_ATTRIBUTE_NAME, getInitiator()); - xml.optAttribute(RESPONDER_ATTRIBUTE_NAME, getResponder()); - xml.optAttribute(ACTION_ATTRIBUTE_NAME, getAction()); - xml.optAttribute(SESSION_ID_ATTRIBUTE_NAME, getSid()); - xml.rightAngleBracket(); - - xml.optElement(reason); - - xml.append(contents); - - return xml; - } - - public static Builder getBuilder() { - return new Builder(); - } - - public static final class Builder { - private String sid; - - private JingleAction action; - - private FullJid initiator; - - private FullJid responder; - - private JingleReason reason; - - private List contents; - - private Builder() { - } - - public Builder setSessionId(String sessionId) { - StringUtils.requireNotNullOrEmpty(sessionId, "Session ID must not be null or empty"); - this.sid = sessionId; - return this; - } - - public Builder setAction(JingleAction action) { - this.action = action; - return this; - } - - public Builder setInitiator(FullJid initator) { - this.initiator = initator; - return this; - } - - public Builder setResponder(FullJid responder) { - this.responder = responder; - return this; - } - - public Builder addJingleContent(JingleContent content) { - if (contents == null) { - contents = new ArrayList<>(1); - } - contents.add(content); - return this; - } - - public Builder setReason(JingleReason.Reason reason) { - this.reason = new JingleReason(reason); - return this; - } - - public Builder setReason(JingleReason reason) { - this.reason = reason; - return this; - } - - public Jingle build() { - return new Jingle(sid, action, initiator, responder, reason, contents); - } - } -} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleAction.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleAction.java index edd2e8033..7b1beb719 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleAction.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleAction.java @@ -44,7 +44,7 @@ public enum JingleAction { transport_replace, ; - private static final Map map = new HashMap( + private static final Map map = new HashMap<>( JingleAction.values().length); static { for (JingleAction jingleAction : JingleAction.values()) { @@ -54,7 +54,7 @@ public enum JingleAction { private final String asString; - private JingleAction() { + JingleAction() { asString = this.name().replace('_', '-'); } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentDescriptionChildElement.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentDescriptionChildElement.java index bb09f205d..9a262b72c 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentDescriptionChildElement.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentDescriptionChildElement.java @@ -20,6 +20,15 @@ import org.jivesoftware.smack.packet.NamedElement; /** * An element found usually in 'description' elements. + * + * + * + * <- We live here. + * + * + * + * + * * */ public abstract class JingleContentDescriptionChildElement implements NamedElement { diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentDescription.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentDescriptionElement.java similarity index 80% rename from smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentDescription.java rename to smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentDescriptionElement.java index d7e5c7933..d34009314 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentDescription.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentDescriptionElement.java @@ -25,15 +25,22 @@ import org.jivesoftware.smack.util.XmlStringBuilder; /** * Jingle content description. + * + * + * <- This element is us. + * + * + * + * * */ -public abstract class JingleContentDescription implements ExtensionElement { +public abstract class JingleContentDescriptionElement implements ExtensionElement { public static final String ELEMENT = "description"; private final List payloads; - protected JingleContentDescription(List payloads) { + protected JingleContentDescriptionElement(List payloads) { if (payloads != null) { this.payloads = Collections.unmodifiableList(payloads); } @@ -51,6 +58,10 @@ public abstract class JingleContentDescription implements ExtensionElement { return payloads; } + public JingleContentDescriptionInfoElement getDescriptionInfo() { + return null; //TODO + } + protected void addExtraAttributes(XmlStringBuilder xml) { } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentTransportInfo.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentDescriptionInfoElement.java similarity index 85% rename from smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentTransportInfo.java rename to smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentDescriptionInfoElement.java index 6e1680046..1287970fe 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentTransportInfo.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentDescriptionInfoElement.java @@ -19,8 +19,8 @@ package org.jivesoftware.smackx.jingle.element; import org.jivesoftware.smack.packet.NamedElement; /** - * Abstract JingleContentTransportInfo element. + * Created by vanitas on 28.07.17. */ -public abstract class JingleContentTransportInfo implements NamedElement { +public abstract class JingleContentDescriptionInfoElement implements NamedElement { } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContent.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentElement.java similarity index 73% rename from smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContent.java rename to smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentElement.java index d18005024..c9a962a4d 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContent.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentElement.java @@ -23,8 +23,13 @@ import org.jivesoftware.smack.util.XmlStringBuilder; /** * Jingle content element. + * + * <- Me. + * ... + * + * */ -public final class JingleContent implements NamedElement { +public final class JingleContentElement implements NamedElement { public static final String ELEMENT = "content"; @@ -64,21 +69,24 @@ public final class JingleContent implements NamedElement { */ private final Senders senders; - private final JingleContentDescription description; + private final JingleContentDescriptionElement description; - private final JingleContentTransport transport; + private final JingleContentTransportElement transport; + + private final JingleContentSecurityElement security; /** * Creates a content description.. */ - private JingleContent(Creator creator, String disposition, String name, Senders senders, - JingleContentDescription description, JingleContentTransport transport) { + private JingleContentElement(Creator creator, String disposition, String name, Senders senders, + JingleContentDescriptionElement description, JingleContentTransportElement transport, JingleContentSecurityElement security) { this.creator = Objects.requireNonNull(creator, "Jingle content creator must not be null"); this.disposition = disposition; this.name = StringUtils.requireNotNullOrEmpty(name, "Jingle content name must not be null or empty"); this.senders = senders; this.description = description; this.transport = transport; + this.security = security; } public Creator getCreator() { @@ -102,28 +110,20 @@ public final class JingleContent implements NamedElement { * * @return The description. */ - public JingleContentDescription getDescription() { + public JingleContentDescriptionElement getDescription() { return description; } /** - * Returns an Iterator for the JingleTransports in the packet. - * - * @return an Iterator for the JingleTransports in the packet. - * @deprecated use {@link #getTransport()} instead. + * Return the transport of the content. + * @return transport. */ - @Deprecated - public JingleContentTransport getJingleTransport() { - return getTransport(); + public JingleContentTransportElement getTransport() { + return transport; } - /** - * Returns an Iterator for the JingleTransports in the packet. - * - * @return an Iterator for the JingleTransports in the packet. - */ - public JingleContentTransport getTransport() { - return transport; + public JingleContentSecurityElement getSecurity() { + return security; } @Override @@ -142,6 +142,7 @@ public final class JingleContent implements NamedElement { xml.optAppend(description); xml.optElement(transport); + xml.optElement(security); xml.closeElement(this); return xml; @@ -160,9 +161,11 @@ public final class JingleContent implements NamedElement { private Senders senders; - private JingleContentDescription description; + private JingleContentDescriptionElement description; - private JingleContentTransport transport; + private JingleContentTransportElement transport; + + private JingleContentSecurityElement security; private Builder() { } @@ -187,7 +190,7 @@ public final class JingleContent implements NamedElement { return this; } - public Builder setDescription(JingleContentDescription description) { + public Builder setDescription(JingleContentDescriptionElement description) { if (this.description != null) { throw new IllegalStateException("Jingle content description already set"); } @@ -195,13 +198,18 @@ public final class JingleContent implements NamedElement { return this; } - public Builder setTransport(JingleContentTransport transport) { + public Builder setTransport(JingleContentTransportElement transport) { this.transport = transport; return this; } - public JingleContent build() { - return new JingleContent(creator, disposition, name, senders, description, transport); + public Builder setSecurity(JingleContentSecurityElement element) { + this.security = element; + return this; + } + + public JingleContentElement build() { + return new JingleContentElement(creator, disposition, name, senders, description, transport, security); } } } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentSecurityElement.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentSecurityElement.java new file mode 100644 index 000000000..08bfbe30f --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentSecurityElement.java @@ -0,0 +1,52 @@ +/** + * + * 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.element; + +import org.jivesoftware.smack.packet.ExtensionElement; + +/** + * Jingle security element. + * + * + * + * + * <- That's me :) + * + * + */ +public abstract class JingleContentSecurityElement implements ExtensionElement { + + public static final String ELEMENT = "security"; + private JingleContentSecurityInfoElement securityInfo; + + public JingleContentSecurityElement() { + + } + + public JingleContentSecurityElement(JingleContentSecurityInfoElement info) { + this.securityInfo = info; + } + + @Override + public String getElementName() { + return ELEMENT; + } + + public JingleContentSecurityInfoElement getSecurityInfo() { + return securityInfo; + } +} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/provider/package-info.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentSecurityInfoElement.java similarity index 73% rename from smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/provider/package-info.java rename to smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentSecurityInfoElement.java index 85163fdeb..758ab6333 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/provider/package-info.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentSecurityInfoElement.java @@ -14,9 +14,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +package org.jivesoftware.smackx.jingle.element; + +import org.jivesoftware.smack.packet.NamedElement; /** - * Smack's API for XEP-0234: Jingle File Transfer. - * Providers. + * Created by vanitas on 19.07.17. */ -package org.jivesoftware.smackx.jingle_filetransfer.provider; +public abstract class JingleContentSecurityInfoElement implements NamedElement { + +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentTransportCandidate.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentTransportCandidateElement.java similarity index 75% rename from smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentTransportCandidate.java rename to smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentTransportCandidateElement.java index be38c8864..c35be1d96 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentTransportCandidate.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentTransportCandidateElement.java @@ -20,9 +20,18 @@ import org.jivesoftware.smack.packet.NamedElement; /** * An element found usually in Jingle 'transport' elements. + * + * + * + * + * <- We are those guys. + * <-/ + * + * + * * */ -public abstract class JingleContentTransportCandidate implements NamedElement { +public abstract class JingleContentTransportCandidateElement implements NamedElement { public static final String ELEMENT = "candidate"; diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentTransport.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentTransportElement.java similarity index 71% rename from smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentTransport.java rename to smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentTransportElement.java index 5b641480f..5961f82ed 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentTransport.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentTransportElement.java @@ -24,35 +24,41 @@ import org.jivesoftware.smack.util.XmlStringBuilder; /** * A jingle transport extension. + * + * + * + * <- Voila. + * + * + * * */ -public abstract class JingleContentTransport implements ExtensionElement { +public abstract class JingleContentTransportElement implements ExtensionElement { public static final String ELEMENT = "transport"; - protected final List candidates; - protected final JingleContentTransportInfo info; + protected final List candidates; + protected final JingleContentTransportInfoElement info; - protected JingleContentTransport(List candidates) { + protected JingleContentTransportElement(List candidates) { this(candidates, null); } - protected JingleContentTransport(List candidates, JingleContentTransportInfo info) { + protected JingleContentTransportElement(List candidates, JingleContentTransportInfoElement info) { if (candidates != null) { this.candidates = Collections.unmodifiableList(candidates); } else { this.candidates = Collections.emptyList(); } - this.info = info; } - public List getCandidates() { + public List getCandidates() { return candidates; } - public JingleContentTransportInfo getInfo() { + public JingleContentTransportInfoElement getInfo() { return info; } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentTransportInfoElement.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentTransportInfoElement.java new file mode 100644 index 000000000..c866e2bcf --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentTransportInfoElement.java @@ -0,0 +1,37 @@ +/** + * + * 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.element; + +import org.jivesoftware.smack.packet.NamedElement; + +/** + * Abstract JingleContentTransportInfo element. + * The JingleContentTransportInfo element can have certain states defined by the respective Transport XEP. + * Examples are Jingle Socks5Bytestream's (Example 5), (Example 7) etc. + * + * + * + * + * <- This is us. + * + * + * + * + */ +public abstract class JingleContentTransportInfoElement implements NamedElement { + +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleElement.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleElement.java new file mode 100644 index 000000000..40ef27735 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleElement.java @@ -0,0 +1,570 @@ +/** + * + * Copyright 2003-2007 Jive Software, 2014-2017 Florian Schmaus + * + * 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.element; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.jivesoftware.smack.packet.IQ; +import org.jivesoftware.smack.packet.XMPPError; +import org.jivesoftware.smack.util.Objects; +import org.jivesoftware.smack.util.StringUtils; + +import org.jxmpp.jid.FullJid; + +/** + * The Jingle element. + * + * @author Florian Schmaus + */ +public final class JingleElement extends IQ { + + public static final String NAMESPACE = "urn:xmpp:jingle:1"; + + public static final String ACTION_ATTRIBUTE_NAME = "action"; + + public static final String INITIATOR_ATTRIBUTE_NAME = "initiator"; + + public static final String RESPONDER_ATTRIBUTE_NAME = "responder"; + + public static final String SESSION_ID_ATTRIBUTE_NAME = "sid"; + + public static final String ELEMENT = "jingle"; + + /** + * The session ID related to this session. The session ID is a unique identifier generated by the initiator. This + * should match the XML Nmtoken production so that XML character escaping is not needed for characters such as &. + */ + private final String sessionId; + + /** + * The jingle action. This attribute is required. + */ + private final JingleAction action; + + private final FullJid initiator; + + private final FullJid responder; + + private final JingleReasonElement reason; + + private final List contents; + + private JingleElement(String sessionId, JingleAction action, FullJid initiator, FullJid responder, JingleReasonElement reason, + List contents) { + super(ELEMENT, NAMESPACE); + this.sessionId = StringUtils.requireNotNullOrEmpty(sessionId, "Jingle session ID must not be null"); + this.action = Objects.requireNonNull(action, "Jingle action must not be null"); + this.initiator = initiator; + this.responder = responder; + this.reason = reason; + if (contents != null) { + this.contents = Collections.unmodifiableList(contents); + } + else { + this.contents = Collections.emptyList(); + } + setType(Type.set); + } + + /** + * Get the initiator. The initiator will be the full JID of the entity that has initiated the flow (which may be + * different to the "from" address in the IQ) + * + * @return the initiator + */ + public FullJid getInitiator() { + return initiator; + } + + /** + * Get the responder. The responder is the full JID of the entity that has replied to the initiation (which may be + * different to the "to" addresss in the IQ). + * + * @return the responder + */ + public FullJid getResponder() { + return responder; + } + + /** + * Returns the session ID related to the session. The session ID is a unique identifier generated by the initiator. + * This should match the XML Nmtoken production so that XML character escaping is not needed for characters such as + * &. + * + * @return Returns the session ID related to the session. + */ + public String getSid() { + return sessionId; + } + + /** + * Get the action specified in the jingle IQ. + * + * @return the action. + */ + public JingleAction getAction() { + return action; + } + + public JingleReasonElement getReason() { + return reason; + } + + /** + * Get a List of the contents. + * + * @return the contents. + */ + public List getContents() { + return contents; + } + + public JingleContentElement getSoleContentOrThrow() { + if (contents.isEmpty()) { + return null; + } + + if (contents.size() == 1) { + return contents.get(0); + } + + throw new IllegalStateException("More than one content is present."); + } + + @Override + protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml) { + xml.optAttribute(INITIATOR_ATTRIBUTE_NAME, getInitiator()); + xml.optAttribute(RESPONDER_ATTRIBUTE_NAME, getResponder()); + xml.optAttribute(ACTION_ATTRIBUTE_NAME, getAction()); + xml.optAttribute(SESSION_ID_ATTRIBUTE_NAME, getSid()); + xml.rightAngleBracket(); + + xml.optElement(reason); + + xml.append(contents); + + return xml; + } + + public static Builder getBuilder() { + return new Builder(); + } + + public static final class Builder { + private String sid; + + private JingleAction action; + + private FullJid initiator; + + private FullJid responder; + + private JingleReasonElement reason; + + private List contents; + + private Builder() { + } + + public Builder setSessionId(String sessionId) { + this.sid = sessionId; + return this; + } + + public Builder setAction(JingleAction action) { + this.action = action; + return this; + } + + public Builder setInitiator(FullJid initator) { + this.initiator = initator; + return this; + } + + public Builder setResponder(FullJid responder) { + this.responder = responder; + return this; + } + + public Builder addJingleContent(JingleContentElement content) { + if (contents == null) { + contents = new ArrayList<>(1); + } + contents.add(content); + return this; + } + + public Builder setReason(JingleReasonElement.Reason reason) { + this.reason = new JingleReasonElement(reason); + return this; + } + + public Builder setReason(JingleReasonElement reason) { + this.reason = reason; + return this; + } + + public JingleElement build() { + return new JingleElement(sid, action, initiator, responder, reason, contents); + } + } + + public static JingleElement createContentAccept(FullJid recipient, String sessionId, List contents) { + JingleElement.Builder builder = JingleElement.getBuilder().setAction(JingleAction.content_accept).setSessionId(sessionId); + + for (JingleContentElement element : contents) { + builder.addJingleContent(element); + } + + JingleElement jingleElement = builder.build(); + jingleElement.setTo(recipient); + + return jingleElement; + } + + /** + * Accept a session. + * XEP-0166 Example 17. + * @param initiator recipient of the stanza. + * @param responder our jid. + * @param sessionId sessionId. + * @param content content + * @return session-accept stanza. + */ + public static JingleElement createSessionAccept(FullJid initiator, + FullJid responder, + String sessionId, + JingleContentElement content) { + return createSessionAccept(initiator, responder, sessionId, Collections.singletonList(content)); + } + + /** + * Accept a session. + * XEP-0166 Example 17. + * @param initiator recipient of the stanza. + * @param responder our jid. + * @param sessionId sessionId. + * @param contents contents + * @return session-accept stanza. + */ + public static JingleElement createSessionAccept(FullJid initiator, + FullJid responder, + String sessionId, + List contents) { + JingleElement.Builder jb = JingleElement.getBuilder(); + jb.setResponder(responder) + .setAction(JingleAction.session_accept) + .setSessionId(sessionId); + + for (JingleContentElement content : contents) { + jb.addJingleContent(content); + } + + JingleElement jingle = jb.build(); + jingle.setTo(initiator); + jingle.setFrom(responder); + + return jingle; + } + + /** + * Initiate a Jingle session. + * XEP-0166 Example 10. + * @param initiator our jid. + * @param responder jid of the recipient. + * @param sessionId sessionId. + * @param content content. + * @return session-initiate stanza. + */ + public static JingleElement createSessionInitiate(FullJid initiator, + FullJid responder, + String sessionId, + JingleContentElement content) { + return createSessionInitiate(initiator, responder, sessionId, Collections.singletonList(content)); + } + + /** + * Initiate a Jingle session. + * XEP-0166 Example 10. + * @param initiator our jid. + * @param responder jid of the recipient. + * @param sessionId sessionId. + * @param contents contents. + * @return session-initiate stanza. + */ + public static JingleElement createSessionInitiate(FullJid initiator, + FullJid responder, + String sessionId, + List contents) { + + JingleElement.Builder builder = JingleElement.getBuilder(); + builder.setAction(JingleAction.session_initiate) + .setSessionId(sessionId) + .setInitiator(initiator); + + for (JingleContentElement content : contents) { + builder.addJingleContent(content); + } + + JingleElement jingle = builder.build(); + jingle.setTo(responder); + + return jingle; + } + + /** + * Create a session ping stanza. + * XEP-0166 Example 32. + * @param recipient recipient of the stanza. + * @param sessionId id of the session. + * @return ping stanza + */ + public static JingleElement createSessionPing(FullJid recipient, String sessionId) { + JingleElement.Builder jb = JingleElement.getBuilder(); + jb.setSessionId(sessionId) + .setAction(JingleAction.session_info); + + JingleElement jingle = jb.build(); + jingle.setTo(recipient); + + return jingle; + } + + /** + * Create a session-terminate stanza. + * XEP-0166 §6.7. + * @param recipient recipient of the stanza. + * @param sessionId sessionId. + * @param reason reason of termination. + * @return session-terminate stanza. + */ + public static JingleElement createSessionTerminate(FullJid recipient, String sessionId, JingleReasonElement reason) { + JingleElement.Builder jb = JingleElement.getBuilder(); + jb.setAction(JingleAction.session_terminate) + .setSessionId(sessionId) + .setReason(reason); + + JingleElement jingle = jb.build(); + jingle.setTo(recipient); + + return jingle; + } + + /** + * Create a session-terminate stanza. + * XEP-0166 §6.7. + * @param recipient recipient of the stanza. + * @param sessionId sessionId. + * @param reason reason of termination. + * @return session-terminate stanza. + */ + public static JingleElement createSessionTerminate(FullJid recipient, String sessionId, JingleReasonElement.Reason reason) { + return createSessionTerminate(recipient, sessionId, new JingleReasonElement(reason)); + } + + /** + * Cancel a single contents transfer. + * XEP-0234 Example 10. + * @param recipient recipient of the stanza. + * @param sessionId sessionId. + * @param contentCreator creator of the content. + * @param contentName name of the content. + * @return session-terminate stanza. + */ + public static JingleElement createSessionTerminateContentCancel(FullJid recipient, String sessionId, + JingleContentElement.Creator contentCreator, String contentName) { + JingleElement.Builder jb = JingleElement.getBuilder(); + jb.setAction(JingleAction.session_terminate) + .setSessionId(sessionId).setReason(JingleReasonElement.Reason.cancel); + + JingleContentElement.Builder cb = JingleContentElement.getBuilder(); + cb.setCreator(contentCreator).setName(contentName); + + JingleElement jingle = jb.addJingleContent(cb.build()).build(); + jingle.setTo(recipient); + + return jingle; + } + + + /** + * Accept a transport. + * XEP-0260 Example 17. + * @param recipient recipient of the stanza + * @param initiator initiator of the session + * @param sessionId sessionId + * @param contentCreator creator of the content + * @param contentName name of the content + * @param transport transport to accept + * @return transport-accept stanza + */ + public static JingleElement createTransportAccept(FullJid initiator, FullJid recipient, String sessionId, + JingleContentElement.Creator contentCreator, + String contentName, JingleContentTransportElement transport) { + JingleElement.Builder jb = JingleElement.getBuilder(); + jb.setAction(JingleAction.transport_accept) + .setInitiator(initiator) + .setSessionId(sessionId); + + JingleContentElement.Builder cb = JingleContentElement.getBuilder(); + cb.setCreator(contentCreator).setName(contentName).setTransport(transport); + + JingleElement jingle = jb.addJingleContent(cb.build()).build(); + jingle.setTo(recipient); + + return jingle; + } + + /** + * Reject a transport. + * XEP-0166 §7.2.14. + * @param recipient recipient of the stanza + * @param initiator initiator of the session + * @param sessionId sessionId + * @param contentCreator creator of the content + * @param contentName name of the content + * @param transport transport to reject + * @return transport-reject stanza + */ + public static JingleElement createTransportReject(FullJid initiator, FullJid recipient, String sessionId, + JingleContentElement.Creator contentCreator, + String contentName, JingleContentTransportElement transport) { + JingleElement.Builder jb = JingleElement.getBuilder(); + jb.setAction(JingleAction.transport_reject) + .setInitiator(initiator) + .setSessionId(sessionId); + + JingleContentElement.Builder cb = JingleContentElement.getBuilder(); + cb.setCreator(contentCreator).setName(contentName).setTransport(transport); + + JingleElement jingle = jb.addJingleContent(cb.build()).build(); + jingle.setTo(recipient); + + return jingle; + } + + /** + * Replace a transport with another one. + * XEP-0260 Example 15. + * @param recipient recipient of the stanza + * @param initiator initiator of the session + * @param sessionId sessionId + * @param contentCreator creator of the content + * @param contentName name of the content + * @param transport proposed transport + * @return transport-replace stanza + */ + public static JingleElement createTransportReplace(FullJid initiator, FullJid recipient, String sessionId, + JingleContentElement.Creator contentCreator, + String contentName, JingleContentTransportElement transport) { + JingleElement.Builder jb = JingleElement.getBuilder() + .setAction(JingleAction.transport_replace) + .setSessionId(sessionId) + .setInitiator(initiator); + + JingleContentElement content = JingleContentElement.getBuilder() + .setCreator(contentCreator) + .setName(contentName) + .setTransport(transport).build(); + + jb.addJingleContent(content); + + JingleElement jingle = jb.build(); + jingle.setTo(recipient); + + return jingle; + } + + /** + * Create an error response to a request with an unknown session id. + * XEP-0166 Example 29. + * @param request request with unknown sessionId. + * @return error stanza. + */ + public static IQ createJingleErrorUnknownSession(JingleElement request) { + XMPPError.Builder error = XMPPError.getBuilder(); + error.setCondition(XMPPError.Condition.item_not_found) + .addExtension(JingleErrorElement.UNKNOWN_SESSION); + return IQ.createErrorResponse(request, error); + } + + /** + * Create an error response to a request coming from a unknown initiator. + * XEP-0166 Example 12. + * @param request request from unknown initiator. + * @return error stanza. + */ + public static IQ createJingleErrorUnknownInitiator(JingleElement request) { + XMPPError.Builder b = XMPPError.getBuilder().setType(XMPPError.Type.CANCEL).setCondition(XMPPError.Condition.service_unavailable); + return IQ.createErrorResponse(request, b); + } + + /** + * Create an error response to a request with an unsupported info. + * XEP-0166 Example 31. + * @param request request with unsupported info. + * @return error stanza. + */ + public static IQ createJingleErrorUnsupportedInfo(JingleElement request) { + XMPPError.Builder error = XMPPError.getBuilder(); + error.setCondition(XMPPError.Condition.feature_not_implemented) + .addExtension(JingleErrorElement.UNSUPPORTED_INFO).setType(XMPPError.Type.MODIFY); + return IQ.createErrorResponse(request, error); + } + + /** + * Create an error response to a tie-breaking request. + * XEP-0166 Example 34. + * @param request tie-breaking request + * @return error stanza + */ + public static IQ createJingleErrorTieBreak(JingleElement request) { + XMPPError.Builder error = XMPPError.getBuilder(); + error.setCondition(XMPPError.Condition.conflict) + .addExtension(JingleErrorElement.TIE_BREAK); + return IQ.createErrorResponse(request, error); + } + + /** + * Create an error response to a request that was out of order. + * TODO: Find example. + * @param request request out of order. + * @return error stanza. + */ + public static IQ createJingleErrorOutOfOrder(JingleElement request) { + XMPPError.Builder error = XMPPError.getBuilder(); + error.setCondition(XMPPError.Condition.unexpected_request) + .addExtension(JingleErrorElement.OUT_OF_ORDER); + return IQ.createErrorResponse(request, error); + } + + /** + * Create an error response to a malformed request. + * XEP-0166 Ex. 16 + * @param request malformed request + * @return error stanza. + */ + public static IQ createJingleErrorMalformedRequest(JingleElement request) { + XMPPError.Builder error = XMPPError.getBuilder(); + error.setType(XMPPError.Type.CANCEL); + error.setCondition(XMPPError.Condition.bad_request); + return IQ.createErrorResponse(request, error); + } +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleError.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleErrorElement.java similarity index 79% rename from smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleError.java rename to smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleErrorElement.java index 77fc356e9..848385ce6 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleError.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleErrorElement.java @@ -22,17 +22,17 @@ import java.util.Locale; import org.jivesoftware.smack.packet.ExtensionElement; import org.jivesoftware.smack.util.XmlStringBuilder; -public final class JingleError implements ExtensionElement { +public final class JingleErrorElement implements ExtensionElement { public static String NAMESPACE = "urn:xmpp:jingle:errors:1"; - public static final JingleError OUT_OF_ORDER = new JingleError("out-of-order"); + static final JingleErrorElement OUT_OF_ORDER = new JingleErrorElement("out-of-order"); - public static final JingleError TIE_BREAK = new JingleError("tie-break"); + static final JingleErrorElement TIE_BREAK = new JingleErrorElement("tie-break"); - public static final JingleError UNKNOWN_SESSION = new JingleError("unknown-session"); + static final JingleErrorElement UNKNOWN_SESSION = new JingleErrorElement("unknown-session"); - public static final JingleError UNSUPPORTED_INFO = new JingleError("unsupported-info"); + static final JingleErrorElement UNSUPPORTED_INFO = new JingleErrorElement("unsupported-info"); private final String errorName; @@ -41,7 +41,7 @@ public final class JingleError implements ExtensionElement { * * @param errorName a name describing the error. */ - private JingleError(final String errorName) { + private JingleErrorElement(final String errorName) { this.errorName = errorName; } @@ -64,7 +64,7 @@ public final class JingleError implements ExtensionElement { /** * Returns a Action instance associated with the String value. */ - public static JingleError fromString(String value) { + public static JingleErrorElement fromString(String value) { value = value.toLowerCase(Locale.US); switch (value) { case "out-of-order": diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleReason.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleReasonElement.java similarity index 64% rename from smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleReason.java rename to smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleReasonElement.java index 29ef9aa71..2f94b9fda 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleReason.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleReasonElement.java @@ -29,7 +29,7 @@ import org.jivesoftware.smack.util.XmlStringBuilder; * @see XEP-0166 § 7.4 * */ -public class JingleReason implements NamedElement { +public class JingleReasonElement implements NamedElement { public static final String ELEMENT = "reason"; @@ -37,22 +37,22 @@ public class JingleReason implements NamedElement { return new AlternativeSession(sessionId); } - public static final JingleReason Busy = new JingleReason(Reason.busy); - public static final JingleReason Cancel = new JingleReason(Reason.cancel); - public static final JingleReason ConnectivityError = new JingleReason(Reason.connectivity_error); - public static final JingleReason Decline = new JingleReason(Reason.decline); - public static final JingleReason Expired = new JingleReason(Reason.expired); - public static final JingleReason FailedApplication = new JingleReason(Reason.failed_application); - public static final JingleReason FailedTransport = new JingleReason(Reason.failed_transport); - public static final JingleReason GeneralError = new JingleReason(Reason.general_error); - public static final JingleReason Gone = new JingleReason(Reason.gone); - public static final JingleReason IncompatibleParameters = new JingleReason(Reason.incompatible_parameters); - public static final JingleReason MediaError = new JingleReason(Reason.media_error); - public static final JingleReason SecurityError = new JingleReason(Reason.security_error); - public static final JingleReason Success = new JingleReason(Reason.success); - public static final JingleReason Timeout = new JingleReason(Reason.timeout); - public static final JingleReason UnsupportedApplications = new JingleReason(Reason.unsupported_applications); - public static final JingleReason UnsupportedTransports = new JingleReason(Reason.unsupported_transports); + public static final JingleReasonElement Busy = new JingleReasonElement(Reason.busy); + public static final JingleReasonElement Cancel = new JingleReasonElement(Reason.cancel); + public static final JingleReasonElement ConnectivityError = new JingleReasonElement(Reason.connectivity_error); + public static final JingleReasonElement Decline = new JingleReasonElement(Reason.decline); + public static final JingleReasonElement Expired = new JingleReasonElement(Reason.expired); + public static final JingleReasonElement FailedApplication = new JingleReasonElement(Reason.failed_application); + public static final JingleReasonElement FailedTransport = new JingleReasonElement(Reason.failed_transport); + public static final JingleReasonElement GeneralError = new JingleReasonElement(Reason.general_error); + public static final JingleReasonElement Gone = new JingleReasonElement(Reason.gone); + public static final JingleReasonElement IncompatibleParameters = new JingleReasonElement(Reason.incompatible_parameters); + public static final JingleReasonElement MediaError = new JingleReasonElement(Reason.media_error); + public static final JingleReasonElement SecurityError = new JingleReasonElement(Reason.security_error); + public static final JingleReasonElement Success = new JingleReasonElement(Reason.success); + public static final JingleReasonElement Timeout = new JingleReasonElement(Reason.timeout); + public static final JingleReasonElement UnsupportedApplications = new JingleReasonElement(Reason.unsupported_applications); + public static final JingleReasonElement UnsupportedTransports = new JingleReasonElement(Reason.unsupported_transports); public enum Reason { alternative_session, @@ -104,7 +104,7 @@ public class JingleReason implements NamedElement { protected final Reason reason; - public JingleReason(Reason reason) { + public JingleReasonElement(Reason reason) { this.reason = reason; } @@ -129,9 +129,9 @@ public class JingleReason implements NamedElement { } - public static class AlternativeSession extends JingleReason { + public static class AlternativeSession extends JingleReasonElement { - public static final String SID = "sid"; + public static final String ATTR_SID = "sid"; private final String sessionId; public AlternativeSession(String sessionId) { @@ -148,9 +148,9 @@ public class JingleReason implements NamedElement { xml.rightAngleBracket(); xml.openElement(reason.asString); - xml.openElement(SID); + xml.openElement(ATTR_SID); xml.append(sessionId); - xml.closeElement(SID); + xml.closeElement(ATTR_SID); xml.closeElement(reason.asString); xml.closeElement(this); diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/UnknownJingleContentDescription.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/UnknownJingleContentDescriptionElement.java similarity index 84% rename from smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/UnknownJingleContentDescription.java rename to smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/UnknownJingleContentDescriptionElement.java index 1f4994fc6..282924588 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/UnknownJingleContentDescription.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/UnknownJingleContentDescriptionElement.java @@ -1,6 +1,6 @@ /** * - * Copyright 2017 Florian Schmaus. + * Copyright 2017 Florian Schmaus, Paul Schaub. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,11 +19,11 @@ package org.jivesoftware.smackx.jingle.element; import org.jivesoftware.smack.packet.StandardExtensionElement; import org.jivesoftware.smack.util.XmlStringBuilder; -public final class UnknownJingleContentDescription extends JingleContentDescription { +public final class UnknownJingleContentDescriptionElement extends JingleContentDescriptionElement { private final StandardExtensionElement standardExtensionElement; - public UnknownJingleContentDescription(StandardExtensionElement standardExtensionElement) { + public UnknownJingleContentDescriptionElement(StandardExtensionElement standardExtensionElement) { super(standardExtensionElement.getElements()); this.standardExtensionElement = standardExtensionElement; } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/UnknownJingleContentSecurityElement.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/UnknownJingleContentSecurityElement.java new file mode 100644 index 000000000..892c33b26 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/UnknownJingleContentSecurityElement.java @@ -0,0 +1,54 @@ +/** + * + * 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.element; + +import org.jivesoftware.smack.packet.StandardExtensionElement; +import org.jivesoftware.smack.util.XmlStringBuilder; + +public final class UnknownJingleContentSecurityElement extends JingleContentSecurityElement { + + private final StandardExtensionElement standardExtensionElement; + + public UnknownJingleContentSecurityElement(StandardExtensionElement standardExtensionElement) { + super(); + this.standardExtensionElement = standardExtensionElement; + } + + @Override + public String getElementName() { + return standardExtensionElement.getElementName(); + } + + @Override + public String getNamespace() { + return standardExtensionElement.getNamespace(); + } + + @Override + public XmlStringBuilder toXML() { + return standardExtensionElement.toXML(); + } + + @Override + public JingleContentSecurityInfoElement getSecurityInfo() { + throw new UnsupportedOperationException(); + } + + public StandardExtensionElement getStandardExtensionElement() { + return standardExtensionElement; + } +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/UnknownJingleContentTransport.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/UnknownJingleContentTransportElement.java similarity index 80% rename from smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/UnknownJingleContentTransport.java rename to smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/UnknownJingleContentTransportElement.java index 8a98f6bae..d92c6dc26 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/UnknownJingleContentTransport.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/UnknownJingleContentTransportElement.java @@ -1,6 +1,6 @@ /** * - * Copyright 2017 Florian Schmaus. + * Copyright 2017 Florian Schmaus, Paul Schaub. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,11 +21,11 @@ import java.util.List; import org.jivesoftware.smack.packet.StandardExtensionElement; import org.jivesoftware.smack.util.XmlStringBuilder; -public final class UnknownJingleContentTransport extends JingleContentTransport { +public final class UnknownJingleContentTransportElement extends JingleContentTransportElement { private final StandardExtensionElement standardExtensionElement; - public UnknownJingleContentTransport(StandardExtensionElement standardExtensionElement) { + public UnknownJingleContentTransportElement(StandardExtensionElement standardExtensionElement) { super(null, null); this.standardExtensionElement = standardExtensionElement; } @@ -46,12 +46,12 @@ public final class UnknownJingleContentTransport extends JingleContentTransport } @Override - public List getCandidates() { + public List getCandidates() { throw new UnsupportedOperationException(); } @Override - public JingleContentTransportInfo getInfo() { + public JingleContentTransportInfoElement getInfo() { throw new UnsupportedOperationException(); } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/exception/FailedTransportException.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/exception/FailedTransportException.java new file mode 100644 index 000000000..fab4e1790 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/exception/FailedTransportException.java @@ -0,0 +1,29 @@ +/** + * + * 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.exception; + +/** + * Created by vanitas on 25.07.17. + */ +public class FailedTransportException extends Exception { + + protected static final long serialVersionUID = 1L; + + public FailedTransportException(Throwable throwable) { + super(throwable); + } +} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/element/JingleFileTransfer.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/exception/UnsupportedDescriptionException.java similarity index 54% rename from smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/element/JingleFileTransfer.java rename to smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/exception/UnsupportedDescriptionException.java index 40dc1aaa2..4d8862901 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/element/JingleFileTransfer.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/exception/UnsupportedDescriptionException.java @@ -14,25 +14,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jivesoftware.smackx.jingle_filetransfer.element; - -import java.util.List; - -import org.jivesoftware.smackx.jingle.element.JingleContentDescription; -import org.jivesoftware.smackx.jingle.element.JingleContentDescriptionChildElement; +package org.jivesoftware.smackx.jingle.exception; /** - * File element. + * Exception that gets thrown when an unknown/unsupported description element is received. */ -public class JingleFileTransfer extends JingleContentDescription { - public static final String NAMESPACE_V5 = "urn:xmpp:jingle:apps:file-transfer:5"; +public class UnsupportedDescriptionException extends Exception { + private static final long serialVersionUID = 1L; - public JingleFileTransfer(List payloads) { - super(payloads); + private final String namespace; + + public UnsupportedDescriptionException(String namespace) { + super("Description with namespace " + namespace + " not supported."); + this.namespace = namespace; } - @Override public String getNamespace() { - return NAMESPACE_V5; + return namespace; } } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/JingleTransportInitiationException.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/exception/UnsupportedSecurityException.java similarity index 59% rename from smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/JingleTransportInitiationException.java rename to smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/exception/UnsupportedSecurityException.java index 8971d2821..810fd0055 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/JingleTransportInitiationException.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/exception/UnsupportedSecurityException.java @@ -14,20 +14,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jivesoftware.smackx.jingle.transports; +package org.jivesoftware.smackx.jingle.exception; /** - * Created by vanitas on 25.06.17. + * Exception that gets thrown when an unknown/unsupported security element gets received. */ -public abstract class JingleTransportInitiationException extends Exception { +public class UnsupportedSecurityException extends Exception { private static final long serialVersionUID = 1L; + private final String namespace; - public static class ProxyError extends JingleTransportInitiationException { - private static final long serialVersionUID = 1L; + public UnsupportedSecurityException(String namespace) { + super("Security with namespace " + namespace + " not supported."); + this.namespace = namespace; } - public static class CandidateError extends JingleTransportInitiationException { - private static final long serialVersionUID = 1L; + public String getNamespace() { + return namespace; } } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/exception/UnsupportedTransportException.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/exception/UnsupportedTransportException.java new file mode 100644 index 000000000..f3b64c45e --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/exception/UnsupportedTransportException.java @@ -0,0 +1,35 @@ +/** + * + * 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.exception; + +/** + * Exception that gets thrown when an unknown/unsupported transport element gets received. + */ +public class UnsupportedTransportException extends Exception { + private static final long serialVersionUID = 1L; + + private final String namespace; + + public UnsupportedTransportException(String namespace) { + super("Transport with namespace " + namespace + " not supported."); + this.namespace = namespace; + } + + public String getNamespace() { + return namespace; + } +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/exception/package-info.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/exception/package-info.java new file mode 100644 index 000000000..de9d53b55 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/exception/package-info.java @@ -0,0 +1,22 @@ +/** + * + * Copyright 2017 Florian Schmaus, 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. + */ + +/** + * Smack's API for XEP-0166: Jingle. + * Exceptions. + */ +package org.jivesoftware.smackx.jingle.exception; diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/package-info.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/package-info.java index 2e7a2ec90..cfdd289cd 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/package-info.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/package-info.java @@ -1,6 +1,6 @@ /** * - * Copyright 2017 Florian Schmaus + * Copyright 2017 Florian Schmaus, Paul Schaub * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/provider/JingleContentDescriptionProvider.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/provider/JingleContentDescriptionProvider.java index 2b5f9c771..488a17ef5 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/provider/JingleContentDescriptionProvider.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/provider/JingleContentDescriptionProvider.java @@ -17,15 +17,15 @@ package org.jivesoftware.smackx.jingle.provider; import org.jivesoftware.smack.provider.ExtensionElementProvider; - -import org.jivesoftware.smackx.jingle.element.JingleContentDescription; +import org.jivesoftware.smackx.jingle.element.JingleContentDescriptionElement; import org.xmlpull.v1.XmlPullParser; -public abstract class JingleContentDescriptionProvider +public abstract class JingleContentDescriptionProvider extends ExtensionElementProvider { @Override public abstract D parse(XmlPullParser parser, int initialDepth) throws Exception; + public abstract String getNamespace(); } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/provider/JingleContentProviderManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/provider/JingleContentProviderManager.java deleted file mode 100644 index 2144d1d01..000000000 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/provider/JingleContentProviderManager.java +++ /dev/null @@ -1,45 +0,0 @@ -/** - * - * Copyright 2017 Florian Schmaus - * - * 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.provider; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -public class JingleContentProviderManager { - - private static final Map> jingleContentDescriptionProviders = new ConcurrentHashMap<>(); - - private static final Map> jingleContentTransportProviders = new ConcurrentHashMap<>(); - - public static JingleContentDescriptionProvider addJingleContentDescriptionProvider(String namespace, - JingleContentDescriptionProvider provider) { - return jingleContentDescriptionProviders.put(namespace, provider); - } - - public static JingleContentDescriptionProvider getJingleContentDescriptionProvider(String namespace) { - return jingleContentDescriptionProviders.get(namespace); - } - - public static JingleContentTransportProvider addJingleContentTransportProvider(String namespace, - JingleContentTransportProvider provider) { - return jingleContentTransportProviders.put(namespace, provider); - } - - public static JingleContentTransportProvider getJingleContentTransportProvider(String namespace) { - return jingleContentTransportProviders.get(namespace); - } -} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/provider/JingleContentSecurityProvider.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/provider/JingleContentSecurityProvider.java new file mode 100644 index 000000000..83403332e --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/provider/JingleContentSecurityProvider.java @@ -0,0 +1,35 @@ +/** + * + * 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.provider; + +import org.jivesoftware.smack.provider.ExtensionElementProvider; +import org.jivesoftware.smackx.jingle.element.JingleContentSecurityElement; + +import org.xmlpull.v1.XmlPullParser; + +/** + * Created by vanitas on 18.07.17. + */ +public abstract class JingleContentSecurityProvider extends ExtensionElementProvider { + +@Override + public abstract D parse(XmlPullParser parser, int initialDepth) throws Exception; + + public abstract String getNamespace(); + +} + diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/provider/JingleContentTransportProvider.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/provider/JingleContentTransportProvider.java index 20c987f62..9fc3ac4da 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/provider/JingleContentTransportProvider.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/provider/JingleContentTransportProvider.java @@ -17,15 +17,15 @@ package org.jivesoftware.smackx.jingle.provider; import org.jivesoftware.smack.provider.ExtensionElementProvider; - -import org.jivesoftware.smackx.jingle.element.JingleContentTransport; +import org.jivesoftware.smackx.jingle.element.JingleContentTransportElement; import org.xmlpull.v1.XmlPullParser; -public abstract class JingleContentTransportProvider +public abstract class JingleContentTransportProvider extends ExtensionElementProvider { @Override public abstract T parse(XmlPullParser parser, int initialDepth) throws Exception; + public abstract String getNamespace(); } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/provider/JingleErrorProvider.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/provider/JingleErrorProvider.java index 14144ae0d..ead817efc 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/provider/JingleErrorProvider.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/provider/JingleErrorProvider.java @@ -17,17 +17,16 @@ package org.jivesoftware.smackx.jingle.provider; import org.jivesoftware.smack.provider.ExtensionElementProvider; - -import org.jivesoftware.smackx.jingle.element.JingleError; +import org.jivesoftware.smackx.jingle.element.JingleErrorElement; import org.xmlpull.v1.XmlPullParser; -public class JingleErrorProvider extends ExtensionElementProvider { +public class JingleErrorProvider extends ExtensionElementProvider { @Override - public JingleError parse(XmlPullParser parser, int initialDepth) throws Exception { + public JingleErrorElement parse(XmlPullParser parser, int initialDepth) throws Exception { String errorName = parser.getName(); - return JingleError.fromString(errorName); + return JingleErrorElement.fromString(errorName); } } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/provider/JingleProvider.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/provider/JingleProvider.java index a040d0ffc..3b64e8cfb 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/provider/JingleProvider.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/provider/JingleProvider.java @@ -22,144 +22,157 @@ import org.jivesoftware.smack.packet.StandardExtensionElement; import org.jivesoftware.smack.parsing.StandardExtensionElementProvider; import org.jivesoftware.smack.provider.IQProvider; import org.jivesoftware.smack.util.ParserUtils; - -import org.jivesoftware.smackx.jingle.element.Jingle; +import org.jivesoftware.smackx.jingle.JingleManager; 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.element.JingleContentTransport; -import org.jivesoftware.smackx.jingle.element.JingleReason; -import org.jivesoftware.smackx.jingle.element.JingleReason.Reason; -import org.jivesoftware.smackx.jingle.element.UnknownJingleContentDescription; -import org.jivesoftware.smackx.jingle.element.UnknownJingleContentTransport; +import org.jivesoftware.smackx.jingle.element.JingleContentDescriptionElement; +import org.jivesoftware.smackx.jingle.element.JingleContentElement; +import org.jivesoftware.smackx.jingle.element.JingleContentSecurityElement; +import org.jivesoftware.smackx.jingle.element.JingleContentTransportElement; +import org.jivesoftware.smackx.jingle.element.JingleElement; +import org.jivesoftware.smackx.jingle.element.JingleReasonElement; +import org.jivesoftware.smackx.jingle.element.UnknownJingleContentDescriptionElement; +import org.jivesoftware.smackx.jingle.element.UnknownJingleContentSecurityElement; +import org.jivesoftware.smackx.jingle.element.UnknownJingleContentTransportElement; import org.jxmpp.jid.FullJid; import org.xmlpull.v1.XmlPullParser; -public class JingleProvider extends IQProvider { +public class JingleProvider extends IQProvider { private static final Logger LOGGER = Logger.getLogger(JingleProvider.class.getName()); @Override - public Jingle parse(XmlPullParser parser, int initialDepth) throws Exception { - Jingle.Builder builder = Jingle.getBuilder(); + public JingleElement parse(XmlPullParser parser, int initialDepth) throws Exception { + JingleElement.Builder builder = JingleElement.getBuilder(); - String actionString = parser.getAttributeValue("", Jingle.ACTION_ATTRIBUTE_NAME); + String actionString = parser.getAttributeValue("", JingleElement.ACTION_ATTRIBUTE_NAME); if (actionString != null) { JingleAction action = JingleAction.fromString(actionString); builder.setAction(action); } - FullJid initiator = ParserUtils.getFullJidAttribute(parser, Jingle.INITIATOR_ATTRIBUTE_NAME); + FullJid initiator = ParserUtils.getFullJidAttribute(parser, JingleElement.INITIATOR_ATTRIBUTE_NAME); builder.setInitiator(initiator); - FullJid responder = ParserUtils.getFullJidAttribute(parser, Jingle.RESPONDER_ATTRIBUTE_NAME); + FullJid responder = ParserUtils.getFullJidAttribute(parser, JingleElement.RESPONDER_ATTRIBUTE_NAME); builder.setResponder(responder); - String sessionId = parser.getAttributeValue("", Jingle.SESSION_ID_ATTRIBUTE_NAME); + String sessionId = parser.getAttributeValue("", JingleElement.SESSION_ID_ATTRIBUTE_NAME); builder.setSessionId(sessionId); outerloop: while (true) { int eventType = parser.next(); switch (eventType) { - case XmlPullParser.START_TAG: - String tagName = parser.getName(); - switch (tagName) { - case JingleContent.ELEMENT: - JingleContent content = parseJingleContent(parser, parser.getDepth()); - builder.addJingleContent(content); - break; - case JingleReason.ELEMENT: - parser.next(); - String reasonString = parser.getName(); - JingleReason reason; - if (reasonString.equals("alternative-session")) { - parser.next(); - String sid = parser.nextText(); - reason = new JingleReason.AlternativeSession(sid); - } else { - reason = new JingleReason(Reason.fromString(reasonString)); + case XmlPullParser.START_TAG: + String tagName = parser.getName(); + switch (tagName) { + case JingleContentElement.ELEMENT: + JingleContentElement content = parseJingleContent(parser, parser.getDepth()); + builder.addJingleContent(content); + break; + case JingleReasonElement.ELEMENT: + parser.next(); + String reasonString = parser.getName(); + JingleReasonElement reason; + if (reasonString.equals("alternative-session")) { + parser.next(); + String sid = parser.nextText(); + reason = new JingleReasonElement.AlternativeSession(sid); + } else { + reason = new JingleReasonElement(JingleReasonElement.Reason.fromString(reasonString)); + } + builder.setReason(reason); + break; + default: + LOGGER.severe("Unknown Jingle element: " + tagName); + break; } - builder.setReason(reason); break; - default: - LOGGER.severe("Unknown Jingle element: " + tagName); - break; - } - break; - case XmlPullParser.END_TAG: - if (parser.getDepth() == initialDepth) { - break outerloop; - } + case XmlPullParser.END_TAG: + if (parser.getDepth() == initialDepth) { + break outerloop; + } } } return builder.build(); } - public static JingleContent parseJingleContent(XmlPullParser parser, final int initialDepth) - throws Exception { - JingleContent.Builder builder = JingleContent.getBuilder(); + private static JingleContentElement parseJingleContent(XmlPullParser parser, final int initialDepth) + throws Exception { + JingleContentElement.Builder builder = JingleContentElement.getBuilder(); - String creatorString = parser.getAttributeValue("", JingleContent.CREATOR_ATTRIBUTE_NAME); - JingleContent.Creator creator = JingleContent.Creator.valueOf(creatorString); + String creatorString = parser.getAttributeValue("", JingleContentElement.CREATOR_ATTRIBUTE_NAME); + JingleContentElement.Creator creator = JingleContentElement.Creator.valueOf(creatorString); builder.setCreator(creator); - String disposition = parser.getAttributeValue("", JingleContent.DISPOSITION_ATTRIBUTE_NAME); + String disposition = parser.getAttributeValue("", JingleContentElement.DISPOSITION_ATTRIBUTE_NAME); builder.setDisposition(disposition); - String name = parser.getAttributeValue("", JingleContent.NAME_ATTRIBUTE_NAME); + String name = parser.getAttributeValue("", JingleContentElement.NAME_ATTRIBUTE_NAME); builder.setName(name); - String sendersString = parser.getAttributeValue("", JingleContent.SENDERS_ATTRIBUTE_NAME); + String sendersString = parser.getAttributeValue("", JingleContentElement.SENDERS_ATTRIBUTE_NAME); if (sendersString != null) { - JingleContent.Senders senders = JingleContent.Senders.valueOf(sendersString); + JingleContentElement.Senders senders = JingleContentElement.Senders.valueOf(sendersString); builder.setSenders(senders); } outerloop: while (true) { int eventType = parser.next(); switch (eventType) { - case XmlPullParser.START_TAG: - String tagName = parser.getName(); - String namespace = parser.getNamespace(); - switch (tagName) { - case JingleContentDescription.ELEMENT: { - JingleContentDescription description; - JingleContentDescriptionProvider provider = JingleContentProviderManager.getJingleContentDescriptionProvider(namespace); - if (provider == null) { - StandardExtensionElement standardExtensionElement = StandardExtensionElementProvider.INSTANCE.parse(parser); - description = new UnknownJingleContentDescription(standardExtensionElement); + case XmlPullParser.START_TAG: + String tagName = parser.getName(); + String namespace = parser.getNamespace(); + switch (tagName) { + case JingleContentDescriptionElement.ELEMENT: { + JingleContentDescriptionElement description; + JingleContentDescriptionProvider provider = JingleManager.getJingleDescriptionProvider(namespace); + if (provider == null) { + StandardExtensionElement standardExtensionElement = StandardExtensionElementProvider.INSTANCE.parse(parser); + description = new UnknownJingleContentDescriptionElement(standardExtensionElement); + } + else { + description = provider.parse(parser); + } + builder.setDescription(description); + break; + } + case JingleContentTransportElement.ELEMENT: { + JingleContentTransportElement transport; + JingleContentTransportProvider provider = JingleManager.getJingleTransportProvider(namespace); + if (provider == null) { + StandardExtensionElement standardExtensionElement = StandardExtensionElementProvider.INSTANCE.parse(parser); + transport = new UnknownJingleContentTransportElement(standardExtensionElement); + } + else { + transport = provider.parse(parser); + } + builder.setTransport(transport); + break; + } + case JingleContentSecurityElement.ELEMENT: { + JingleContentSecurityElement security; + JingleContentSecurityProvider provider = JingleManager.getJingleSecurityProvider(namespace); + if (provider == null) { + StandardExtensionElement standardExtensionElement = StandardExtensionElementProvider.INSTANCE.parse(parser); + security = new UnknownJingleContentSecurityElement(standardExtensionElement); + } else { + security = provider.parse(parser); + } + builder.setSecurity(security); + break; + } + default: + LOGGER.severe("Unknown Jingle content element: " + tagName); + break; } - else { - description = provider.parse(parser); - } - builder.setDescription(description); break; - } - case JingleContentTransport.ELEMENT: { - JingleContentTransport transport; - JingleContentTransportProvider provider = JingleContentProviderManager.getJingleContentTransportProvider(namespace); - if (provider == null) { - StandardExtensionElement standardExtensionElement = StandardExtensionElementProvider.INSTANCE.parse(parser); - transport = new UnknownJingleContentTransport(standardExtensionElement); + case XmlPullParser.END_TAG: + if (parser.getDepth() == initialDepth) { + break outerloop; } - else { - transport = provider.parse(parser); - } - builder.setTransport(transport); - break; - } - default: - LOGGER.severe("Unknown Jingle content element: " + tagName); - break; - } - break; - case XmlPullParser.END_TAG: - if (parser.getDepth() == initialDepth) { - break outerloop; - } } } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/BytestreamSessionEstablishedListener.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/BytestreamSessionEstablishedListener.java new file mode 100644 index 000000000..b0f306318 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/BytestreamSessionEstablishedListener.java @@ -0,0 +1,30 @@ +/** + * + * 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.transport; + +import org.jivesoftware.smackx.bytestreams.BytestreamSession; + +/** + * Listener that can be registered to get notified about established Bytestreams. + */ +public interface BytestreamSessionEstablishedListener { + + void onBytestreamSessionEstablished(BytestreamSession session); + + void onBytestreamSessionFailed(Exception exception); + +} 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 new file mode 100644 index 000000000..9403f75ec --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_ibb/JingleIBBTransport.java @@ -0,0 +1,150 @@ +/** + * + * 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.transport.jingle_ibb; + +import java.util.logging.Level; +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.smack.util.StringUtils; +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.component.JingleSession; +import org.jivesoftware.smackx.jingle.component.JingleTransport; +import org.jivesoftware.smackx.jingle.component.JingleTransportCandidate; +import org.jivesoftware.smackx.jingle.element.JingleContentTransportElement; +import org.jivesoftware.smackx.jingle.element.JingleContentTransportInfoElement; +import org.jivesoftware.smackx.jingle.element.JingleElement; +import org.jivesoftware.smackx.jingle.transport.jingle_ibb.element.JingleIBBTransportElement; + +/** + * Jingle InBandBytestream Transport component. + */ +public class JingleIBBTransport extends JingleTransport { + private static final Logger LOGGER = Logger.getLogger(JingleIBBTransport.class.getName()); + + public static final String NAMESPACE_V1 = "urn:xmpp:jingle:transports:ibb:1"; + public static final String NAMESPACE = NAMESPACE_V1; + + public static final Short DEFAULT_BLOCK_SIZE = 4096; + public static final Short MAX_BLOCKSIZE = 8192; + + private final String streamId; + private Short blockSize; + + public JingleIBBTransport(String streamId, Short blockSize) { + this.streamId = streamId; + this.blockSize = blockSize; + } + + public JingleIBBTransport() { + this(StringUtils.randomString(10), DEFAULT_BLOCK_SIZE); + } + + public Short getBlockSize() { + return blockSize; + } + + public String getStreamId() { + return streamId; + } + + @Override + public JingleIBBTransportElement getElement() { + return new JingleIBBTransportElement(streamId, blockSize); + } + + @Override + public String getNamespace() { + return NAMESPACE; + } + + @Override + public void handleSessionAccept(JingleContentTransportElement transportElement, XMPPConnection connection) { + JingleIBBTransportElement element = (JingleIBBTransportElement) transportElement; + blockSize = (blockSize < element.getBlockSize() ? blockSize : element.getBlockSize()); + } + + @Override + public void establishIncomingBytestreamSession(final XMPPConnection connection, final JingleTransportCallback callback, final JingleSession session) { + final InBandBytestreamManager inBandBytestreamManager = InBandBytestreamManager.getByteStreamManager(connection); + LOGGER.log(Level.INFO, "Listen for incoming IBB transports from " + session.getPeer() + ":" + getStreamId()); + InBandBytestreamListener bytestreamListener = new InBandBytestreamListener() { + @Override + public void incomingBytestreamRequest(InBandBytestreamRequest request) { + LOGGER.log(Level.INFO, "Incoming IBB stream: " + request.getFrom().asFullJidIfPossible() + ":" + request.getSessionID()); + if (request.getFrom().asFullJidIfPossible().equals(session.getPeer()) + && request.getSessionID().equals(getStreamId())) { + + inBandBytestreamManager.removeIncomingBytestreamListener(this); + + BytestreamSession bytestreamSession; + try { + bytestreamSession = request.accept(); + } catch (InterruptedException | SmackException e) { + callback.onTransportFailed(e); + return; + } + + JingleIBBTransport.this.bytestreamSession = bytestreamSession; + callback.onTransportReady(JingleIBBTransport.this.bytestreamSession); + } + } + }; + + InBandBytestreamManager.getByteStreamManager(connection) + .addIncomingBytestreamListener(bytestreamListener); + } + + @Override + public void establishOutgoingBytestreamSession(XMPPConnection connection, JingleTransportCallback callback, final JingleSession session) { + InBandBytestreamManager inBandBytestreamManager = InBandBytestreamManager.getByteStreamManager(connection); + inBandBytestreamManager.setDefaultBlockSize(blockSize); + try { + JingleIBBTransport.this.bytestreamSession = inBandBytestreamManager.establishSession(session.getPeer(), getStreamId()); + callback.onTransportReady(this.bytestreamSession); + } catch (SmackException.NoResponseException | XMPPException.XMPPErrorException | InterruptedException | SmackException.NotConnectedException e) { + callback.onTransportFailed(e); + } + } + + @Override + public void cleanup() { + // Nothing to do. + } + + @Override + public void addOurCandidate(JingleTransportCandidate candidate) { + // Sorry, we don't want any candidates. + } + + @Override + public void prepare(XMPPConnection connection) { + // Nothing to do. + } + + @Override + public IQ handleTransportInfo(JingleContentTransportInfoElement info, JingleElement wrapping) { + return IQ.createResultIQ(wrapping); + } +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_ibb/JingleIBBTransportAdapter.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_ibb/JingleIBBTransportAdapter.java new file mode 100644 index 000000000..6eb8c0071 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_ibb/JingleIBBTransportAdapter.java @@ -0,0 +1,37 @@ +/** + * + * 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.transport.jingle_ibb; + +import org.jivesoftware.smackx.jingle.adapter.JingleTransportAdapter; +import org.jivesoftware.smackx.jingle.element.JingleContentTransportElement; +import org.jivesoftware.smackx.jingle.transport.jingle_ibb.element.JingleIBBTransportElement; + +/** + * Adapter for Jingle InBandBytestream transports. + */ +public class JingleIBBTransportAdapter implements JingleTransportAdapter { + @Override + public JingleIBBTransport transportFromElement(JingleContentTransportElement element) { + JingleIBBTransportElement transport = (JingleIBBTransportElement) element; + return new JingleIBBTransport(transport.getStreamId(), transport.getBlockSize()); + } + + @Override + public String getNamespace() { + return JingleIBBTransport.NAMESPACE; + } +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_ibb/JingleIBBTransportManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_ibb/JingleIBBTransportManager.java new file mode 100644 index 000000000..b936044e3 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_ibb/JingleIBBTransportManager.java @@ -0,0 +1,92 @@ +/** + * + * 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.transport.jingle_ibb; + +import java.util.WeakHashMap; + +import org.jivesoftware.smack.Manager; +import org.jivesoftware.smack.XMPPConnection; +import org.jivesoftware.smackx.disco.ServiceDiscoveryManager; +import org.jivesoftware.smackx.jingle.JingleManager; +import org.jivesoftware.smackx.jingle.JingleTransportManager; +import org.jivesoftware.smackx.jingle.component.JingleContent; +import org.jivesoftware.smackx.jingle.component.JingleTransport; +import org.jivesoftware.smackx.jingle.element.JingleContentTransportElement; +import org.jivesoftware.smackx.jingle.transport.jingle_ibb.provider.JingleIBBTransportProvider; + +/** + * Created by vanitas on 21.07.17. + */ +public final class JingleIBBTransportManager extends Manager implements JingleTransportManager { + + private static final WeakHashMap INSTANCES = new WeakHashMap<>(); + + static { + JingleManager.addJingleTransportAdapter(new JingleIBBTransportAdapter()); + JingleManager.addJingleTransportProvider(new JingleIBBTransportProvider()); + } + + private JingleIBBTransportManager(XMPPConnection connection) { + super(connection); + ServiceDiscoveryManager.getInstanceFor(connection).addFeature(getNamespace()); + JingleManager jingleManager = JingleManager.getInstanceFor(connection); + jingleManager.addJingleTransportManager(this); + } + + public static JingleIBBTransportManager getInstanceFor(XMPPConnection connection) { + JingleIBBTransportManager manager = INSTANCES.get(connection); + + if (manager == null) { + manager = new JingleIBBTransportManager(connection); + INSTANCES.put(connection, manager); + } + + return manager; + } + + @Override + public String getNamespace() { + return JingleIBBTransport.NAMESPACE; + } + + @Override + public JingleTransport createTransportForInitiator(JingleContent content) { + return new JingleIBBTransport(); + } + + @Override + public JingleTransport createTransportForResponder(JingleContent content, JingleTransport peersTransport) { + JingleIBBTransport other = (JingleIBBTransport) peersTransport; + return new JingleIBBTransport(other.getStreamId(), (short) Math.min(other.getBlockSize(), JingleIBBTransport.MAX_BLOCKSIZE)); + } + + @Override + public JingleTransport createTransportForResponder(JingleContent content, JingleContentTransportElement peersTransportElement) { + JingleIBBTransport other = new JingleIBBTransportAdapter().transportFromElement(peersTransportElement); + return createTransportForResponder(content, other); + } + + @Override + public int getPriority() { + return -1; + } + + @Override + public int compareTo(JingleTransportManager other) { + return getPriority() > other.getPriority() ? 1 : -1; + } +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_ibb/element/JingleIBBTransport.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_ibb/element/JingleIBBTransportElement.java similarity index 61% rename from smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_ibb/element/JingleIBBTransport.java rename to smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_ibb/element/JingleIBBTransportElement.java index 59afc8d58..d4c259f3d 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_ibb/element/JingleIBBTransport.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_ibb/element/JingleIBBTransportElement.java @@ -14,56 +14,36 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jivesoftware.smackx.jingle.transports.jingle_ibb.element; +package org.jivesoftware.smackx.jingle.transport.jingle_ibb.element; -import org.jivesoftware.smack.util.StringUtils; import org.jivesoftware.smack.util.XmlStringBuilder; - -import org.jivesoftware.smackx.jingle.element.JingleContentTransport; +import org.jivesoftware.smackx.jingle.element.JingleContentTransportElement; +import org.jivesoftware.smackx.jingle.transport.jingle_ibb.JingleIBBTransport; /** * Transport Element for JingleInBandBytestream transports. */ -public class JingleIBBTransport extends JingleContentTransport { - public static final String NAMESPACE_V1 = "urn:xmpp:jingle:transports:ibb:1"; +public class JingleIBBTransportElement extends JingleContentTransportElement { public static final String ATTR_BLOCK_SIZE = "block-size"; public static final String ATTR_SID = "sid"; - public static final short DEFAULT_BLOCK_SIZE = 4096; - - private final short blockSize; private final String sid; + private final Short blockSize; - public JingleIBBTransport() { - this(DEFAULT_BLOCK_SIZE); - } - - public JingleIBBTransport(String sid) { - this(DEFAULT_BLOCK_SIZE, sid); - } - - public JingleIBBTransport(short blockSize) { - this(blockSize, StringUtils.randomString(24)); - } - - public JingleIBBTransport(short blockSize, String sid) { + public JingleIBBTransportElement(String streamId, Short blockSize) { super(null); - if (blockSize > 0) { - this.blockSize = blockSize; - } else { - this.blockSize = DEFAULT_BLOCK_SIZE; - } - this.sid = sid; + this.sid = streamId; + this.blockSize = blockSize != null ? blockSize : JingleIBBTransport.DEFAULT_BLOCK_SIZE; } - public String getSessionId() { - return sid; - } - - public short getBlockSize() { + public Short getBlockSize() { return blockSize; } + public String getStreamId() { + return sid; + } + @Override protected void addExtraAttributes(XmlStringBuilder xml) { xml.attribute(ATTR_BLOCK_SIZE, blockSize); @@ -72,12 +52,12 @@ public class JingleIBBTransport extends JingleContentTransport { @Override public String getNamespace() { - return NAMESPACE_V1; + return JingleIBBTransport.NAMESPACE; } @Override public boolean equals(Object other) { - if (other == null || !(other instanceof JingleIBBTransport)) { + if (other == null || !(other instanceof JingleIBBTransportElement)) { return false; } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_ibb/element/package-info.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_ibb/element/package-info.java similarity index 91% rename from smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_ibb/element/package-info.java rename to smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_ibb/element/package-info.java index 3cbb5462e..144290cb3 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_ibb/element/package-info.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_ibb/element/package-info.java @@ -19,4 +19,4 @@ * Smack's API for XEP-0261: Jingle In-Band Bytestreams. * Element classes. */ -package org.jivesoftware.smackx.jingle.transports.jingle_ibb.element; +package org.jivesoftware.smackx.jingle.transport.jingle_ibb.element; diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/package-info.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_ibb/package-info.java similarity index 92% rename from smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/package-info.java rename to smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_ibb/package-info.java index 9cfe634a5..71fc7d0f7 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/package-info.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_ibb/package-info.java @@ -18,4 +18,4 @@ /** * Smack's API for XEP-0261: Jingle In-Band Bytestreams. */ -package org.jivesoftware.smackx.jingle.transports; +package org.jivesoftware.smackx.jingle.transport.jingle_ibb; diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_ibb/provider/JingleIBBTransportProvider.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_ibb/provider/JingleIBBTransportProvider.java similarity index 55% rename from smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_ibb/provider/JingleIBBTransportProvider.java rename to smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_ibb/provider/JingleIBBTransportProvider.java index 73b027748..015f4ff16 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_ibb/provider/JingleIBBTransportProvider.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_ibb/provider/JingleIBBTransportProvider.java @@ -14,27 +14,28 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jivesoftware.smackx.jingle.transports.jingle_ibb.provider; +package org.jivesoftware.smackx.jingle.transport.jingle_ibb.provider; +import org.jivesoftware.smack.util.ParserUtils; import org.jivesoftware.smackx.jingle.provider.JingleContentTransportProvider; -import org.jivesoftware.smackx.jingle.transports.jingle_ibb.element.JingleIBBTransport; +import org.jivesoftware.smackx.jingle.transport.jingle_ibb.JingleIBBTransport; +import org.jivesoftware.smackx.jingle.transport.jingle_ibb.element.JingleIBBTransportElement; import org.xmlpull.v1.XmlPullParser; /** * Parse JingleByteStreamTransport elements. */ -public class JingleIBBTransportProvider extends JingleContentTransportProvider { +public class JingleIBBTransportProvider extends JingleContentTransportProvider { @Override - public JingleIBBTransport parse(XmlPullParser parser, int initialDepth) throws Exception { - String blockSizeString = parser.getAttributeValue(null, JingleIBBTransport.ATTR_BLOCK_SIZE); - String sid = parser.getAttributeValue(null, JingleIBBTransport.ATTR_SID); + public JingleIBBTransportElement parse(XmlPullParser parser, int initialDepth) throws Exception { + Short blockSize = ParserUtils.getShortAttribute(parser, JingleIBBTransportElement.ATTR_BLOCK_SIZE); + String sid = parser.getAttributeValue(null, JingleIBBTransportElement.ATTR_SID); + return new JingleIBBTransportElement(sid, blockSize); + } - short blockSize = -1; - if (blockSizeString != null) { - blockSize = Short.valueOf(blockSizeString); - } - - return new JingleIBBTransport(blockSize, sid); + @Override + public String getNamespace() { + return JingleIBBTransport.NAMESPACE; } } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_ibb/provider/package-info.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_ibb/provider/package-info.java similarity index 91% rename from smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_ibb/provider/package-info.java rename to smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_ibb/provider/package-info.java index 3bf479e8e..6cb217eb6 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_ibb/provider/package-info.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_ibb/provider/package-info.java @@ -19,4 +19,4 @@ * Smack's API for XEP-0261: Jingle In-Band Bytestreams. * Provider classes. */ -package org.jivesoftware.smackx.jingle.transports.jingle_ibb.provider; +package org.jivesoftware.smackx.jingle.transport.jingle_ibb.provider; 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 new file mode 100644 index 000000000..e3b7e676b --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/JingleS5BTransport.java @@ -0,0 +1,462 @@ +/** + * + * 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.transport.jingle_s5b; + +import java.io.IOException; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.TimeoutException; +import java.util.logging.Level; +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.smack.util.Async; +import org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamSession; +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.component.JingleSession; +import org.jivesoftware.smackx.jingle.component.JingleTransport; +import org.jivesoftware.smackx.jingle.component.JingleTransportCandidate; +import org.jivesoftware.smackx.jingle.element.JingleContentTransportCandidateElement; +import org.jivesoftware.smackx.jingle.element.JingleContentTransportElement; +import org.jivesoftware.smackx.jingle.element.JingleContentTransportInfoElement; +import org.jivesoftware.smackx.jingle.element.JingleElement; +import org.jivesoftware.smackx.jingle.exception.FailedTransportException; +import org.jivesoftware.smackx.jingle.transport.jingle_s5b.element.JingleS5BTransportCandidateElement; +import org.jivesoftware.smackx.jingle.transport.jingle_s5b.element.JingleS5BTransportElement; +import org.jivesoftware.smackx.jingle.transport.jingle_s5b.element.JingleS5BTransportInfoElement; + +import org.jxmpp.jid.FullJid; + +/** + * Jingle SOCKS5Bytestream transport component. + */ +public class JingleS5BTransport extends JingleTransport { + + private static final Logger LOGGER = Logger.getLogger(JingleS5BTransport.class.getName()); + + public static final String NAMESPACE_V1 = "urn:xmpp:jingle:transports:s5b:1"; + public static final String NAMESPACE = NAMESPACE_V1; + + private static final int MAX_TIMEOUT = 10 * 1000; + + private final String sid; + + private String ourDstAddr; + private String theirDstAddr; + + private Bytestream.Mode mode; + + // PEERS candidate of OUR choice. + private JingleS5BTransportCandidate ourSelectedCandidate; + private JingleS5BTransportCandidate theirSelectedCandidate; + + private JingleTransportCallback callback; + + /** + * Create transport as initiator. + * @param initiator initiator of the Jingle session. + * @param responder responder. + * @param sid sessionId of the Jingle session. + * @param mode TCP/UDP. + * @param ourCandidates our proxy candidates. + */ + JingleS5BTransport(FullJid initiator, FullJid responder, String sid, Bytestream.Mode mode, List> ourCandidates) { + this.sid = sid; + this.mode = mode; + this.ourDstAddr = Socks5Utils.createDigest(sid, initiator, responder); + Socks5Proxy.getSocks5Proxy().addTransfer(ourDstAddr); + + for (JingleTransportCandidate c : ourCandidates) { + addOurCandidate(c); + } + } + + /** + * Create simple transport as responder. + * @param initiator initiator of the Jingle session. + * @param responder responder. + * @param ourCandidates our proxy candidates. + * @param other transport of the other party. + */ + JingleS5BTransport(FullJid initiator, FullJid responder, List> ourCandidates, JingleS5BTransport other) { + this.sid = other.getStreamId(); + this.mode = other.mode; + this.ourDstAddr = Socks5Utils.createDigest(sid, responder, initiator); + Socks5Proxy.getSocks5Proxy().addTransfer(ourDstAddr); + this.theirDstAddr = other.theirDstAddr; + + for (JingleTransportCandidate c : ourCandidates) { + addOurCandidate(c); + } + + for (JingleTransportCandidate c : other.getTheirCandidates()) { + addTheirCandidate(c); + } + } + + /** + * Create custom transport as responder. + * @param sid sessionId of the Jingle session. + * @param mode UPD/TCP. + * @param ourDstAddr SOCKS5 destination address (digest) + * @param theirDstAddr SOCKS5 destination address (digest) + * @param ourCandidates our proxy candidates. + * @param theirCandidates their proxy candidates. + */ + JingleS5BTransport(String sid, Bytestream.Mode mode, String ourDstAddr, String theirDstAddr, List> ourCandidates, List> theirCandidates) { + this.sid = sid; + this.mode = mode; + this.ourDstAddr = ourDstAddr; + Socks5Proxy.getSocks5Proxy().addTransfer(ourDstAddr); + this.theirDstAddr = theirDstAddr; + + for (JingleTransportCandidate c : (ourCandidates != null ? ourCandidates : + Collections.emptySet())) { + addOurCandidate(c); + } + + for (JingleTransportCandidate c : (theirCandidates != null ? theirCandidates : + Collections.emptySet())) { + addTheirCandidate(c); + } + } + + /** + * Copy constructor. + * @param original which will be copied. + */ + public JingleS5BTransport(JingleS5BTransport original) { + this.sid = original.sid; + this.ourDstAddr = original.ourDstAddr; + this.theirDstAddr = original.theirDstAddr; + this.mode = original.mode; + + for (JingleTransportCandidate c : original.getOurCandidates()) { + addOurCandidate(new JingleS5BTransportCandidate((JingleS5BTransportCandidate) c)); + } + + for (JingleTransportCandidate c : original.getTheirCandidates()) { + addTheirCandidate(new JingleS5BTransportCandidate((JingleS5BTransportCandidate) c)); + } + } + + @Override + public JingleS5BTransportElement getElement() { + JingleS5BTransportElement.Builder builder = JingleS5BTransportElement.getBuilder() + .setStreamId(sid) + .setDestinationAddress(ourDstAddr) + .setMode(mode); + + for (JingleTransportCandidate candidate : getOurCandidates()) { + builder.addTransportCandidate((JingleS5BTransportCandidateElement) candidate.getElement()); + } + + return builder.build(); + } + + public String getStreamId() { + return sid; + } + + public String getOurDstAddr() { + return ourDstAddr; + } + + public String getTheirDstAddr() { + return theirDstAddr; + } + + public Bytestream.Mode getMode() { + return mode; + } + + @Override + public String getNamespace() { + return NAMESPACE; + } + + @Override + public void prepare(XMPPConnection connection) { + JingleSession session = getParent().getParent(); + if (getOurDstAddr() == null) { + ourDstAddr = Socks5Utils.createDigest(getStreamId(), session.getOurJid(), session.getPeer()); + Socks5Proxy.getSocks5Proxy().addTransfer(ourDstAddr); + } + + if (mode == null) { + mode = Bytestream.Mode.tcp; + } + + if (getOurCandidates().size() == 0) { + List> candidates = JingleS5BTransportManager.getInstanceFor(connection).collectCandidates(); + for (JingleTransportCandidate c : candidates) { + addOurCandidate(c); + } + } + } + + @Override + public void establishIncomingBytestreamSession(XMPPConnection connection, JingleTransportCallback callback, JingleSession session) + throws SmackException.NotConnectedException, InterruptedException { + LOGGER.log(Level.INFO, "Establishing incoming bytestream."); + this.callback = callback; + establishBytestreamSession(connection); + } + + @Override + public void establishOutgoingBytestreamSession(XMPPConnection connection, JingleTransportCallback callback, JingleSession session) + throws SmackException.NotConnectedException, InterruptedException { + LOGGER.log(Level.INFO, "Establishing outgoing bytestream."); + this.callback = callback; + establishBytestreamSession(connection); + } + + @SuppressWarnings("ReferenceEquality") + private void establishBytestreamSession(XMPPConnection connection) + throws SmackException.NotConnectedException, InterruptedException { + Socks5Proxy.getSocks5Proxy().addTransfer(ourDstAddr); + this.ourSelectedCandidate = connectToCandidates(MAX_TIMEOUT); + + if (ourSelectedCandidate == CANDIDATE_FAILURE) { + connection.createStanzaCollectorAndSend(JingleS5BTransportManager.createCandidateError(this)); + return; + } + + if (ourSelectedCandidate == null) { + throw new AssertionError("MUST NOT BE NULL."); + } + + connection.createStanzaCollectorAndSend(JingleS5BTransportManager.createCandidateUsed(this, ourSelectedCandidate)); + connectIfReady(); + } + + @SuppressWarnings("ReferenceEquality") + private JingleS5BTransportCandidate connectToCandidates(int timeout) { + + if (getTheirCandidates().size() == 0) { + LOGGER.log(Level.INFO, "They provided 0 candidates."); + return CANDIDATE_FAILURE; + } + + int _timeout = timeout / getTheirCandidates().size(); //TODO: Wise? + for (JingleTransportCandidate c : getTheirCandidates()) { + JingleS5BTransportCandidate candidate = (JingleS5BTransportCandidate) c; + try { + return candidate.connect(_timeout, true); + } catch (IOException | TimeoutException | InterruptedException | SmackException | XMPPException e) { + LOGGER.log(Level.WARNING, "Exception while connecting to candidate: " + e, e); + } + } + + // Failed to connect to any candidate. + return CANDIDATE_FAILURE; + } + + @Override + public void cleanup() { + Socks5Proxy.getSocks5Proxy().removeTransfer(ourDstAddr); + } + + @SuppressWarnings("ReferenceEquality") + private void connectIfReady() { + final JingleSession session = getParent().getParent(); + + if (ourSelectedCandidate == null || theirSelectedCandidate == null) { + // Not yet ready if we or peer did not yet decide on a candidate. + LOGGER.log(Level.INFO, "Not ready."); + return; + } + + if (ourSelectedCandidate == CANDIDATE_FAILURE && theirSelectedCandidate == CANDIDATE_FAILURE) { + LOGGER.log(Level.INFO, "Failure."); + callback.onTransportFailed(new FailedTransportException(null)); + return; + } + + LOGGER.log(Level.INFO, (session.isInitiator() ? "Initiator" : "Responder") + " is ready."); + + //Determine nominated candidate. + JingleS5BTransportCandidate nominated; + if (ourSelectedCandidate != CANDIDATE_FAILURE && theirSelectedCandidate != CANDIDATE_FAILURE) { + + if (ourSelectedCandidate.getPriority() > theirSelectedCandidate.getPriority()) { + nominated = ourSelectedCandidate; + } else if (ourSelectedCandidate.getPriority() < theirSelectedCandidate.getPriority()) { + nominated = theirSelectedCandidate; + } else { + nominated = getParent().getParent().isInitiator() ? ourSelectedCandidate : theirSelectedCandidate; + } + + } else if (ourSelectedCandidate != CANDIDATE_FAILURE) { + nominated = ourSelectedCandidate; + } else { + nominated = theirSelectedCandidate; + } + + boolean isProxy = nominated.getType() == JingleS5BTransportCandidateElement.Type.proxy; + + if (nominated == theirSelectedCandidate) { + + LOGGER.log(Level.INFO, "Their choice, so our proposed candidate is used."); + + try { + nominated = nominated.connect(MAX_TIMEOUT, false); + } catch (InterruptedException | IOException | XMPPException | SmackException | TimeoutException e) { + LOGGER.log(Level.INFO, "Could not connect to our candidate.", e); + + Async.go(new Runnable() { + @Override + public void run() { + try { + session.getJingleManager().getConnection().createStanzaCollectorAndSend(JingleS5BTransportManager.createProxyError(JingleS5BTransport.this)); + } catch (SmackException.NotConnectedException | InterruptedException e1) { + LOGGER.log(Level.SEVERE, "Could not send proxy error: " + e, e); + } + } + }); + + callback.onTransportFailed(new S5BTransportException.CandidateError(e)); + return; + } + + if (isProxy) { + LOGGER.log(Level.INFO, "Send candidate-activate."); + JingleElement candidateActivate = JingleS5BTransportManager.createCandidateActivated((JingleS5BTransport) nominated.getParent(), nominated); + + try { + session.getJingleManager().getConnection().createStanzaCollectorAndSend(candidateActivate) + .nextResultOrThrow(); + } catch (InterruptedException | XMPPException.XMPPErrorException | SmackException.NotConnectedException | SmackException.NoResponseException e) { + LOGGER.log(Level.WARNING, "Could not send candidate-activated", e); + callback.onTransportFailed(new S5BTransportException.ProxyError(e)); + return; + } + } + + LOGGER.log(Level.INFO, "Start transmission on " + nominated.getCandidateId()); + this.bytestreamSession = new Socks5BytestreamSession(nominated.getSocket(), !isProxy); + callback.onTransportReady(this.bytestreamSession); + + } + //Our choice + else { + LOGGER.log(Level.INFO, "Our choice, so their candidate was used."); + if (!isProxy) { + LOGGER.log(Level.INFO, "Start transmission on " + nominated.getCandidateId()); + this.bytestreamSession = new Socks5BytestreamSession(nominated.getSocket(), true); + callback.onTransportReady(this.bytestreamSession); + } else { + LOGGER.log(Level.INFO, "Our choice was their external proxy. wait for candidate-activate."); + } + } + } + + @Override + public void handleSessionAccept(JingleContentTransportElement transportElement, XMPPConnection connection) { + JingleS5BTransportElement transport = (JingleS5BTransportElement) transportElement; + theirDstAddr = transport.getDestinationAddress(); + for (JingleContentTransportCandidateElement c : transport.getCandidates()) { + JingleS5BTransportCandidateElement candidate = (JingleS5BTransportCandidateElement) c; + addTheirCandidate(new JingleS5BTransportCandidate(candidate)); + } + } + + @Override + public IQ handleTransportInfo(JingleContentTransportInfoElement info, JingleElement wrapping) { + switch (info.getElementName()) { + + case JingleS5BTransportInfoElement.CandidateUsed.ELEMENT: + handleCandidateUsed((JingleS5BTransportInfoElement) info, wrapping); + break; + + case JingleS5BTransportInfoElement.CandidateActivated.ELEMENT: + handleCandidateActivate((JingleS5BTransportInfoElement) info); + break; + + case JingleS5BTransportInfoElement.CandidateError.ELEMENT: + handleCandidateError((JingleS5BTransportInfoElement) info); + break; + + case JingleS5BTransportInfoElement.ProxyError.ELEMENT: + handleProxyError((JingleS5BTransportInfoElement) info); + break; + + default: + throw new AssertionError("Unknown transport-info element: " + info.getElementName()); + } + + return IQ.createResultIQ(wrapping); + } + + private void handleCandidateUsed(JingleS5BTransportInfoElement info, JingleElement wrapping) { + JingleManager jingleManager = getParent().getParent().getJingleManager(); + String candidateId = ((JingleS5BTransportInfoElement.CandidateUsed) info).getCandidateId(); + + // Received second candidate-used -> out-of-order! + if (theirSelectedCandidate != null) { + try { + jingleManager.getConnection().sendStanza(JingleElement.createJingleErrorOutOfOrder(wrapping)); + //jingleManager.getConnection().createStanzaCollectorAndSend(JingleElement.createJingleErrorOutOfOrder(wrapping)); + } catch (SmackException.NotConnectedException | InterruptedException e) { + LOGGER.log(Level.SEVERE, "Could not respond to candidate-used transport-info: " + e, e); + } + return; + } + + for (JingleTransportCandidate jingleTransportCandidate : getOurCandidates()) { + JingleS5BTransportCandidate candidate = (JingleS5BTransportCandidate) jingleTransportCandidate; + if (candidate.getCandidateId().equals(candidateId)) { + theirSelectedCandidate = candidate; + } + } + + if (theirSelectedCandidate == null) { + LOGGER.log(Level.SEVERE, "ILLEGAL CANDIDATE ID!!!"); + //TODO: Alert! Illegal candidateId! + } + + connectIfReady(); + } + + private void handleCandidateActivate(JingleS5BTransportInfoElement info) { + this.bytestreamSession = new Socks5BytestreamSession(ourSelectedCandidate.getSocket(), + ourSelectedCandidate.getStreamHost().getJID().asBareJid().equals(getParent().getParent().getPeer().asBareJid())); + callback.onTransportReady(this.bytestreamSession); + } + + private void handleCandidateError(JingleS5BTransportInfoElement info) { + theirSelectedCandidate = CANDIDATE_FAILURE; + connectIfReady(); + } + + private void handleProxyError(JingleS5BTransportInfoElement info) { + callback.onTransportFailed(new S5BTransportException.ProxyError(null)); + } + + /** + * Internal dummy candidate used to represent failure. + * Kinda depressing, isn't it? + */ + private final static JingleS5BTransportCandidate CANDIDATE_FAILURE = new JingleS5BTransportCandidate(null, null, -1, null); +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/JingleS5BTransportAdapter.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/JingleS5BTransportAdapter.java new file mode 100644 index 000000000..490a4168e --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/JingleS5BTransportAdapter.java @@ -0,0 +1,49 @@ +/** + * + * 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.transport.jingle_s5b; + +import java.util.ArrayList; + +import org.jivesoftware.smackx.jingle.adapter.JingleTransportAdapter; +import org.jivesoftware.smackx.jingle.component.JingleTransportCandidate; +import org.jivesoftware.smackx.jingle.element.JingleContentTransportCandidateElement; +import org.jivesoftware.smackx.jingle.element.JingleContentTransportElement; +import org.jivesoftware.smackx.jingle.transport.jingle_s5b.element.JingleS5BTransportCandidateElement; +import org.jivesoftware.smackx.jingle.transport.jingle_s5b.element.JingleS5BTransportElement; + +/** + * Adapter for Jingle SOCKS5Bytestream components. + */ +public class JingleS5BTransportAdapter implements JingleTransportAdapter { + + @Override + public JingleS5BTransport transportFromElement(JingleContentTransportElement element) { + JingleS5BTransportElement s5b = (JingleS5BTransportElement) element; + ArrayList> candidates = new ArrayList<>(); + + for (JingleContentTransportCandidateElement e : element.getCandidates()) { + candidates.add(JingleS5BTransportCandidate.fromElement((JingleS5BTransportCandidateElement) e)); + } + + return new JingleS5BTransport(s5b.getStreamId(), s5b.getMode(), null, s5b.getDestinationAddress(), null, candidates); + } + + @Override + public String getNamespace() { + return JingleS5BTransport.NAMESPACE; + } +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/JingleS5BTransportCandidate.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/JingleS5BTransportCandidate.java new file mode 100644 index 000000000..b377fd2d1 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/JingleS5BTransportCandidate.java @@ -0,0 +1,152 @@ +/** + * + * 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.transport.jingle_s5b; + +import java.io.IOException; +import java.net.Socket; +import java.util.concurrent.TimeoutException; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.jivesoftware.smack.SmackException; +import org.jivesoftware.smack.XMPPException; +import org.jivesoftware.smackx.bytestreams.socks5.Socks5Client; +import org.jivesoftware.smackx.bytestreams.socks5.Socks5ClientForInitiator; +import org.jivesoftware.smackx.bytestreams.socks5.Socks5Utils; +import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream; +import org.jivesoftware.smackx.jingle.component.JingleContent; +import org.jivesoftware.smackx.jingle.component.JingleSession; +import org.jivesoftware.smackx.jingle.component.JingleTransportCandidate; +import org.jivesoftware.smackx.jingle.transport.jingle_s5b.element.JingleS5BTransportCandidateElement; + +/** + * Jingle SOCKS5Bytestream transport candidate. + */ +public class JingleS5BTransportCandidate extends JingleTransportCandidate { + private static final Logger LOGGER = Logger.getLogger(JingleS5BTransportCandidate.class.getName()); + + private final String candidateId; + private final Bytestream.StreamHost streamHost; + private final JingleS5BTransportCandidateElement.Type type; + + private Socket socket; + + JingleS5BTransportCandidate(JingleS5BTransportCandidateElement element) { + this(element.getCandidateId(), new Bytestream.StreamHost(element.getJid(), element.getHost(), element.getPort()), element.getPriority(), element.getType()); + } + + JingleS5BTransportCandidate(String candidateId, + Bytestream.StreamHost streamHost, + int priority, + JingleS5BTransportCandidateElement.Type type) { + this.candidateId = candidateId; + this.streamHost = streamHost; + this.type = type; + + setPriority(priority); + } + + JingleS5BTransportCandidate(JingleS5BTransportCandidate other) { + this(other.candidateId, + other.getStreamHost(), + other.getPriority(), + other.type); + } + + static JingleS5BTransportCandidate fromElement(JingleS5BTransportCandidateElement element) { + return new JingleS5BTransportCandidate(element.getCandidateId(), element.getStreamHost(), element.getPriority(), element.getType()); + } + + String getCandidateId() { + return candidateId; + } + + public Bytestream.StreamHost getStreamHost() { + return streamHost; + } + + public JingleS5BTransportCandidateElement.Type getType() { + return type; + } + + @Override + public JingleS5BTransportCandidateElement getElement() { + return new JingleS5BTransportCandidateElement( + getCandidateId(), getStreamHost().getAddress(), + getStreamHost().getJID(), getStreamHost().getPort(), + getPriority(), getType()); + } + + public JingleS5BTransportCandidate connect(int timeout, boolean peersProposal) throws InterruptedException, TimeoutException, SmackException, XMPPException, IOException { + JingleS5BTransport transport = (JingleS5BTransport) getParent(); + + switch (getType()) { + case proxy: + case direct: + Socks5Client client; + if (peersProposal) { + String dstAddr = transport.getTheirDstAddr(); + if (dstAddr == null) { + dstAddr = Socks5Utils.createDigest(transport.getStreamId(), transport.getParent().getParent().getPeer(), transport.getParent().getParent().getOurJid()); + } + LOGGER.log(Level.INFO, "Connect to foreign candidate " + getCandidateId() + " using " + dstAddr); + LOGGER.log(Level.INFO, getStreamHost().getAddress() + ":" + getStreamHost().getPort() + " " + getStreamHost().getJID().toString() + " " + getType()); + client = new Socks5Client(getStreamHost(), dstAddr); + } else { + LOGGER.log(Level.INFO, "Connect to our candidate " + getCandidateId() + " using " + transport.getOurDstAddr()); + LOGGER.log(Level.INFO, getStreamHost().getAddress() + ":" + getStreamHost().getPort() + " " + getStreamHost().getJID().toString() + " " + getType()); + JingleContent content = transport.getParent(); + JingleSession session = content.getParent(); + client = new Socks5ClientForInitiator(getStreamHost(), transport.getOurDstAddr(), session.getJingleManager().getConnection(), transport.getStreamId(), session.getPeer()); + } + this.socket = client.getSocket(timeout); + break; + + default: + LOGGER.log(Level.INFO, "Unsupported candidate type: " + getType()); + break; + } + + return this; + } + + public Socket getSocket() { + return socket; + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + + if (!(other instanceof JingleS5BTransportCandidate)) { + return false; + } + + JingleS5BTransportCandidate o = (JingleS5BTransportCandidate) other; + + return o.getCandidateId().equals(this.getCandidateId()) && + o.getType() == this.getType() && + o.getStreamHost().equals(this.getStreamHost()); + } + + @Override + public int hashCode() { + return getCandidateId().hashCode() + 3 * getType().hashCode() + 5 * getStreamHost().hashCode(); + } +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/JingleS5BTransportManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/JingleS5BTransportManager.java new file mode 100644 index 000000000..fbcb1a554 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/JingleS5BTransportManager.java @@ -0,0 +1,308 @@ +/** + * + * 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.transport.jingle_s5b; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.WeakHashMap; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.jivesoftware.smack.ConnectionListener; +import org.jivesoftware.smack.Manager; +import org.jivesoftware.smack.SmackException; +import org.jivesoftware.smack.XMPPConnection; +import org.jivesoftware.smack.XMPPException; +import org.jivesoftware.smack.packet.IQ; +import org.jivesoftware.smack.util.StringUtils; +import org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamManager; +import org.jivesoftware.smackx.bytestreams.socks5.Socks5Proxy; +import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream; +import org.jivesoftware.smackx.disco.ServiceDiscoveryManager; +import org.jivesoftware.smackx.jingle.JingleManager; +import org.jivesoftware.smackx.jingle.JingleTransportManager; +import org.jivesoftware.smackx.jingle.component.JingleContent; +import org.jivesoftware.smackx.jingle.component.JingleSession; +import org.jivesoftware.smackx.jingle.component.JingleTransport; +import org.jivesoftware.smackx.jingle.component.JingleTransportCandidate; +import org.jivesoftware.smackx.jingle.element.JingleAction; +import org.jivesoftware.smackx.jingle.element.JingleContentElement; +import org.jivesoftware.smackx.jingle.element.JingleContentTransportElement; +import org.jivesoftware.smackx.jingle.element.JingleElement; +import org.jivesoftware.smackx.jingle.transport.jingle_s5b.element.JingleS5BTransportCandidateElement; +import org.jivesoftware.smackx.jingle.transport.jingle_s5b.element.JingleS5BTransportElement; +import org.jivesoftware.smackx.jingle.transport.jingle_s5b.element.JingleS5BTransportInfoElement; +import org.jivesoftware.smackx.jingle.transport.jingle_s5b.provider.JingleS5BTransportProvider; + +import org.jxmpp.jid.Jid; + +/** + * Manager for Jingle SOCKS5 Bytestream transports (XEP-0261). + */ +public final class JingleS5BTransportManager extends Manager implements JingleTransportManager { + + private static final Logger LOGGER = Logger.getLogger(JingleS5BTransportManager.class.getName()); + private final Socks5BytestreamManager socks5BytestreamManager = Socks5BytestreamManager.getBytestreamManager(connection()); + + private static final WeakHashMap INSTANCES = new WeakHashMap<>(); + + private List localStreamHosts = null; + private List availableStreamHosts = null; + + public static boolean useLocalCandidates = true; + public static boolean useExternalCandidates = true; + + static { + JingleManager.addJingleTransportAdapter(new JingleS5BTransportAdapter()); + JingleManager.addJingleTransportProvider(new JingleS5BTransportProvider()); + } + + private JingleS5BTransportManager(XMPPConnection connection) { + super(connection); + ServiceDiscoveryManager.getInstanceFor(connection).addFeature(getNamespace()); + JingleManager jingleManager = JingleManager.getInstanceFor(connection); + jingleManager.addJingleTransportManager(this); + + connection.addConnectionListener(connectionListener); + } + + public static JingleS5BTransportManager getInstanceFor(XMPPConnection connection) { + JingleS5BTransportManager manager = INSTANCES.get(connection); + if (manager == null) { + manager = new JingleS5BTransportManager(connection); + INSTANCES.put(connection, manager); + } + return manager; + } + + @Override + public String getNamespace() { + return JingleS5BTransport.NAMESPACE; + } + + @Override + public JingleTransport createTransportForInitiator(JingleContent content) { + JingleSession session = content.getParent(); + String sid = StringUtils.randomString(24); + List> candidates = collectCandidates(); + return new JingleS5BTransport(session.getInitiator(), session.getResponder(), sid, Bytestream.Mode.tcp, candidates); + } + + @Override + public JingleTransport createTransportForResponder(JingleContent content, JingleTransport peersTransport) { + JingleSession session = content.getParent(); + return new JingleS5BTransport(session.getInitiator(), session.getResponder(), collectCandidates(), (JingleS5BTransport) peersTransport); + } + + @Override + public JingleTransport createTransportForResponder(JingleContent content, JingleContentTransportElement peersTransportElement) { + JingleS5BTransport other = new JingleS5BTransportAdapter().transportFromElement(peersTransportElement); + return createTransportForResponder(content, other); + } + + @Override + public int getPriority() { + return 10000; // SOCKS5 has a high priority + } + + List> collectCandidates() { + List> candidates = new ArrayList<>(); + + //Local host + if (JingleS5BTransportManager.isUseLocalCandidates()) { + for (Bytestream.StreamHost host : getLocalStreamHosts()) { + candidates.add(new JingleS5BTransportCandidate(StringUtils.randomString(16), host, 100, JingleS5BTransportCandidateElement.Type.proxy)); + } + } + + List remoteHosts = Collections.emptyList(); + if (JingleS5BTransportManager.isUseExternalCandidates()) { + try { + remoteHosts = getServersStreamHosts(); + } catch (InterruptedException | XMPPException.XMPPErrorException | SmackException.NotConnectedException | SmackException.NoResponseException e) { + LOGGER.log(Level.WARNING, "Could not determine available StreamHosts.", e); + } + } + + for (Bytestream.StreamHost host : remoteHosts) { + candidates.add(new JingleS5BTransportCandidate(StringUtils.randomString(16), host, 0, JingleS5BTransportCandidateElement.Type.proxy)); + } + + return candidates; + } + + private List queryServersStreamHosts() throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException { + List proxies = socks5BytestreamManager.determineProxies(); + return determineStreamHostInfo(proxies); + } + + private List queryLocalStreamHosts() { + return socks5BytestreamManager.getLocalStreamHost(); + } + + private List getServersStreamHosts() throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException { + if (availableStreamHosts == null) { + availableStreamHosts = queryServersStreamHosts(); + } + return availableStreamHosts; + } + + private List getLocalStreamHosts() { + if (localStreamHosts == null) { + localStreamHosts = queryLocalStreamHosts(); + } + return localStreamHosts; + } + + private List determineStreamHostInfo(List proxies) { + List streamHosts = new ArrayList<>(); + + Iterator iterator = proxies.iterator(); + while (iterator.hasNext()) { + Jid proxy = iterator.next(); + Bytestream request = new Bytestream(); + request.setType(IQ.Type.get); + request.setTo(proxy); + + try { + Bytestream response = connection().createStanzaCollectorAndSend(request).nextResultOrThrow(); + streamHosts.addAll(response.getStreamHosts()); + } + catch (Exception e) { + iterator.remove(); + } + } + + return streamHosts; + } + + private static JingleElement createTransportInfo(JingleS5BTransport transport, JingleS5BTransportInfoElement info) { + JingleContent content = transport.getParent(); + JingleSession session = content.getParent(); + + JingleElement.Builder jb = JingleElement.getBuilder() + .setSessionId(session.getSessionId()) + .setAction(JingleAction.transport_info); + + if (session.isInitiator()) { + jb.setInitiator(session.getInitiator()); + } else { + jb.setResponder(session.getResponder()); + } + + JingleContentElement.Builder cb = JingleContentElement.getBuilder() + .setCreator(content.getCreator()) + .setName(content.getName()) + .setSenders(content.getSenders()); + + JingleS5BTransportElement.Builder tb = JingleS5BTransportElement.getBuilder() + .setTransportInfo(info) + .setStreamId(transport.getStreamId()); + + JingleElement jingle = jb.addJingleContent(cb.setTransport(tb.build()).build()).build(); + jingle.setFrom(session.getOurJid()); + jingle.setTo(session.getPeer()); + + return jingle; + } + + static JingleElement createCandidateUsed(JingleS5BTransport transport, JingleS5BTransportCandidate candidate) { + return createTransportInfo(transport, new JingleS5BTransportInfoElement.CandidateUsed(candidate.getCandidateId())); + } + + static JingleElement createCandidateError(JingleS5BTransport transport) { + return createTransportInfo(transport, JingleS5BTransportInfoElement.CandidateError.INSTANCE); + } + + static JingleElement createProxyError(JingleS5BTransport transport) { + return createTransportInfo(transport, JingleS5BTransportInfoElement.ProxyError.INSTANCE); + } + + static JingleElement createCandidateActivated(JingleS5BTransport transport, JingleS5BTransportCandidate candidate) { + return createTransportInfo(transport, new JingleS5BTransportInfoElement.CandidateActivated(candidate.getCandidateId())); + } + + public static void setUseLocalCandidates(boolean localCandidates) { + JingleS5BTransportManager.useLocalCandidates = localCandidates; + } + + public static void setUseExternalCandidates(boolean externalCandidates) { + JingleS5BTransportManager.useExternalCandidates = externalCandidates; + } + + public static boolean isUseLocalCandidates() { + return useLocalCandidates; + } + + public static boolean isUseExternalCandidates() { + return useExternalCandidates; + } + + @Override + public int compareTo(JingleTransportManager other) { + return getPriority() > other.getPriority() ? 1 : -1; + } + + private final ConnectionListener connectionListener = new ConnectionListener() { + + @Override + public void connected(XMPPConnection connection) { + } + + @Override + public void authenticated(XMPPConnection connection, boolean resumed) { + if (connection.equals(connection())) { + try { + Socks5Proxy socks5Proxy = Socks5Proxy.getSocks5Proxy(); + if (!socks5Proxy.isRunning()) { + socks5Proxy.start(); + } + localStreamHosts = queryLocalStreamHosts(); + availableStreamHosts = queryServersStreamHosts(); + } catch (InterruptedException | SmackException.NoResponseException | SmackException.NotConnectedException | XMPPException.XMPPErrorException e) { + LOGGER.log(Level.WARNING, "Could not query available StreamHosts: " + e, e); + } + } + } + + @Override + public void connectionClosed() { + Socks5Proxy proxy = Socks5Proxy.getSocks5Proxy(); + if (proxy.isRunning()) { + Socks5Proxy.getSocks5Proxy().stop(); + } + } + + @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/transport/jingle_s5b/S5BTransportException.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/S5BTransportException.java new file mode 100644 index 000000000..cb9714d33 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/S5BTransportException.java @@ -0,0 +1,47 @@ +/** + * + * 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.transport.jingle_s5b; + +import org.jivesoftware.smackx.jingle.exception.FailedTransportException; + +/** + * Created by vanitas on 25.07.17. + */ +public class S5BTransportException extends FailedTransportException { + + protected static final long serialVersionUID = 1L; + + private S5BTransportException(Throwable throwable) { + super(throwable); + } + + public static class CandidateError extends S5BTransportException { + protected static final long serialVersionUID = 1L; + + CandidateError(Throwable throwable) { + super(throwable); + } + } + + public static class ProxyError extends S5BTransportException { + protected static final long serialVersionUID = 1L; + + ProxyError(Throwable throwable) { + super(throwable); + } + } +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_s5b/elements/JingleS5BTransportCandidate.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/element/JingleS5BTransportCandidateElement.java similarity index 88% rename from smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_s5b/elements/JingleS5BTransportCandidate.java rename to smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/element/JingleS5BTransportCandidateElement.java index b16e5f563..778ba38cb 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_s5b/elements/JingleS5BTransportCandidate.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/element/JingleS5BTransportCandidateElement.java @@ -14,15 +14,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jivesoftware.smackx.jingle.transports.jingle_s5b.elements; - -import java.util.logging.Logger; +package org.jivesoftware.smackx.jingle.transport.jingle_s5b.element; import org.jivesoftware.smack.util.Objects; import org.jivesoftware.smack.util.StringUtils; import org.jivesoftware.smack.util.XmlStringBuilder; import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream; -import org.jivesoftware.smackx.jingle.element.JingleContentTransportCandidate; +import org.jivesoftware.smackx.jingle.element.JingleContentTransportCandidateElement; import org.jxmpp.jid.Jid; import org.jxmpp.jid.impl.JidCreate; @@ -31,9 +29,7 @@ import org.jxmpp.stringprep.XmppStringprepException; /** * TransportCandidate for Jingle Socks5Bytestream transports. */ -public final class JingleS5BTransportCandidate extends JingleContentTransportCandidate { - - private static final Logger LOGGER = Logger.getLogger(JingleS5BTransportCandidate.class.getName()); +public final class JingleS5BTransportCandidateElement extends JingleContentTransportCandidateElement { public static final String ATTR_CID = "cid"; public static final String ATTR_HOST = "host"; @@ -49,7 +45,7 @@ public final class JingleS5BTransportCandidate extends JingleContentTransportCan private final int priority; private final Type type; - public JingleS5BTransportCandidate(String candidateId, String host, Jid jid, int port, int priority, Type type) { + public JingleS5BTransportCandidateElement(String candidateId, String host, Jid jid, int port, int priority, Type type) { Objects.requireNonNull(candidateId); Objects.requireNonNull(host); @@ -70,7 +66,7 @@ public final class JingleS5BTransportCandidate extends JingleContentTransportCan this.type = type; } - public JingleS5BTransportCandidate(Bytestream.StreamHost streamHost, int priority, Type type) { + public JingleS5BTransportCandidateElement(Bytestream.StreamHost streamHost, int priority, Type type) { this(StringUtils.randomString(24), streamHost.getAddress(), streamHost.getJID(), streamHost.getPort(), priority, type); } @@ -197,8 +193,8 @@ public final class JingleS5BTransportCandidate extends JingleContentTransportCan return this; } - public JingleS5BTransportCandidate build() { - return new JingleS5BTransportCandidate(cid, host, jid, port, priority, type); + public JingleS5BTransportCandidateElement build() { + return new JingleS5BTransportCandidateElement(cid, host, jid, port, priority, type); } } } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_s5b/elements/JingleS5BTransport.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/element/JingleS5BTransportElement.java similarity index 71% rename from smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_s5b/elements/JingleS5BTransport.java rename to smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/element/JingleS5BTransportElement.java index 8845d122d..e43c709ba 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_s5b/elements/JingleS5BTransport.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/element/JingleS5BTransportElement.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jivesoftware.smackx.jingle.transports.jingle_s5b.elements; +package org.jivesoftware.smackx.jingle.transport.jingle_s5b.element; import java.util.ArrayList; import java.util.List; @@ -22,33 +22,33 @@ import java.util.List; import org.jivesoftware.smack.util.StringUtils; import org.jivesoftware.smack.util.XmlStringBuilder; import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream; -import org.jivesoftware.smackx.jingle.element.JingleContentTransport; -import org.jivesoftware.smackx.jingle.element.JingleContentTransportCandidate; -import org.jivesoftware.smackx.jingle.element.JingleContentTransportInfo; +import org.jivesoftware.smackx.jingle.element.JingleContentTransportCandidateElement; +import org.jivesoftware.smackx.jingle.element.JingleContentTransportElement; +import org.jivesoftware.smackx.jingle.element.JingleContentTransportInfoElement; +import org.jivesoftware.smackx.jingle.transport.jingle_s5b.JingleS5BTransport; /** * Socks5Bytestream transport element. */ -public class JingleS5BTransport extends JingleContentTransport { - public static final String NAMESPACE_V1 = "urn:xmpp:jingle:transports:s5b:1"; +public class JingleS5BTransportElement extends JingleContentTransportElement { public static final String ATTR_DSTADDR = "dstaddr"; public static final String ATTR_MODE = "mode"; public static final String ATTR_SID = "sid"; - private final String streamId; + private final String sid; private final String dstAddr; private final Bytestream.Mode mode; - protected JingleS5BTransport(List candidates, JingleContentTransportInfo info, String streamId, String dstAddr, Bytestream.Mode mode) { + protected JingleS5BTransportElement(String streamId, List candidates, JingleContentTransportInfoElement info, String dstAddr, Bytestream.Mode mode) { super(candidates, info); StringUtils.requireNotNullOrEmpty(streamId, "sid MUST be neither null, nor empty."); - this.streamId = streamId; + this.sid = streamId; this.dstAddr = dstAddr; this.mode = mode; } public String getStreamId() { - return streamId; + return sid; } public String getDestinationAddress() { @@ -61,23 +61,23 @@ public class JingleS5BTransport extends JingleContentTransport { @Override public String getNamespace() { - return NAMESPACE_V1; + return JingleS5BTransport.NAMESPACE; } @Override protected void addExtraAttributes(XmlStringBuilder xml) { xml.optAttribute(ATTR_DSTADDR, dstAddr); xml.optAttribute(ATTR_MODE, mode); - xml.attribute(ATTR_SID, streamId); + xml.attribute(ATTR_SID, sid); } public boolean hasCandidate(String candidateId) { return getCandidate(candidateId) != null; } - public JingleS5BTransportCandidate getCandidate(String candidateId) { - for (JingleContentTransportCandidate c : candidates) { - JingleS5BTransportCandidate candidate = (JingleS5BTransportCandidate) c; + public JingleS5BTransportCandidateElement getCandidate(String candidateId) { + for (JingleContentTransportCandidateElement c : candidates) { + JingleS5BTransportCandidateElement candidate = (JingleS5BTransportCandidateElement) c; if (candidate.getCandidateId().equals(candidateId)) { return candidate; } @@ -93,8 +93,8 @@ public class JingleS5BTransport extends JingleContentTransport { private String streamId; private String dstAddr; private Bytestream.Mode mode; - private final ArrayList candidates = new ArrayList<>(); - private JingleContentTransportInfo info; + private final ArrayList candidates = new ArrayList<>(); + private JingleContentTransportInfoElement info; public Builder setStreamId(String sid) { this.streamId = sid; @@ -111,7 +111,7 @@ public class JingleS5BTransport extends JingleContentTransport { return this; } - public Builder addTransportCandidate(JingleS5BTransportCandidate candidate) { + public Builder addTransportCandidate(JingleS5BTransportCandidateElement candidate) { if (info != null) { throw new IllegalStateException("Builder has already an info set. " + "The transport can only have either an info or transport candidates, not both."); @@ -120,7 +120,7 @@ public class JingleS5BTransport extends JingleContentTransport { return this; } - public Builder setTransportInfo(JingleContentTransportInfo info) { + public Builder setTransportInfo(JingleContentTransportInfoElement info) { if (!candidates.isEmpty()) { throw new IllegalStateException("Builder has already at least one candidate set. " + "The transport can only have either an info or transport candidates, not both."); @@ -132,24 +132,26 @@ public class JingleS5BTransport extends JingleContentTransport { return this; } + public JingleS5BTransportElement build() { + return new JingleS5BTransportElement(streamId, candidates, info, dstAddr, mode); + } + public Builder setCandidateUsed(String candidateId) { - return setTransportInfo(new JingleS5BTransportInfo.CandidateUsed(candidateId)); + return setTransportInfo(new JingleS5BTransportInfoElement.CandidateUsed(candidateId)); } public Builder setCandidateActivated(String candidateId) { - return setTransportInfo(new JingleS5BTransportInfo.CandidateActivated(candidateId)); + return setTransportInfo(new JingleS5BTransportInfoElement.CandidateActivated(candidateId)); } public Builder setCandidateError() { - return setTransportInfo(JingleS5BTransportInfo.CandidateError.INSTANCE); + return setTransportInfo(JingleS5BTransportInfoElement.CandidateError.INSTANCE); } public Builder setProxyError() { - return setTransportInfo(JingleS5BTransportInfo.ProxyError.INSTANCE); + return setTransportInfo(JingleS5BTransportInfoElement.ProxyError.INSTANCE); } - public JingleS5BTransport build() { - return new JingleS5BTransport(candidates, info, streamId, dstAddr, mode); - } } } + diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_s5b/elements/JingleS5BTransportInfo.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/element/JingleS5BTransportInfoElement.java similarity index 85% rename from smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_s5b/elements/JingleS5BTransportInfo.java rename to smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/element/JingleS5BTransportInfoElement.java index 167b3a8f1..e9fef6ea9 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_s5b/elements/JingleS5BTransportInfo.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/element/JingleS5BTransportInfoElement.java @@ -14,22 +14,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jivesoftware.smackx.jingle.transports.jingle_s5b.elements; +package org.jivesoftware.smackx.jingle.transport.jingle_s5b.element; import org.jivesoftware.smack.util.XmlStringBuilder; -import org.jivesoftware.smackx.jingle.element.JingleContentTransportInfo; +import org.jivesoftware.smackx.jingle.element.JingleContentTransportInfoElement; /** * Class representing possible SOCKS5 TransportInfo elements. */ -public abstract class JingleS5BTransportInfo extends JingleContentTransportInfo { +public abstract class JingleS5BTransportInfoElement extends JingleContentTransportInfoElement { - public static abstract class JingleS5BCandidateTransportInfo extends JingleS5BTransportInfo { + public static abstract class JingleS5BCandidateTransportInfoElement extends JingleS5BTransportInfoElement { public static final String ATTR_CID = "cid"; private final String candidateId; - protected JingleS5BCandidateTransportInfo(String candidateId) { + JingleS5BCandidateTransportInfoElement(String candidateId) { this.candidateId = candidateId; } @@ -48,11 +48,11 @@ public abstract class JingleS5BTransportInfo extends JingleContentTransportInfo @Override public final boolean equals(Object other) { - if (!(other instanceof JingleS5BCandidateTransportInfo)) { + if (!(other instanceof JingleS5BCandidateTransportInfoElement)) { return false; } - JingleS5BCandidateTransportInfo otherCandidateTransportInfo = (JingleS5BCandidateTransportInfo) other; + JingleS5BCandidateTransportInfoElement otherCandidateTransportInfo = (JingleS5BCandidateTransportInfoElement) other; return toXML().equals(otherCandidateTransportInfo.toXML()); } @@ -62,8 +62,8 @@ public abstract class JingleS5BTransportInfo extends JingleContentTransportInfo } } - public static final class CandidateActivated extends JingleS5BCandidateTransportInfo { - public static final String ELEMENT = "candidate-activated"; + public static final class CandidateActivated extends JingleS5BCandidateTransportInfoElement { + public static final String ELEMENT = "activated"; public CandidateActivated(String candidateId) { super(candidateId); @@ -75,7 +75,8 @@ public abstract class JingleS5BTransportInfo extends JingleContentTransportInfo } } - public static final class CandidateUsed extends JingleS5BCandidateTransportInfo { + + public static final class CandidateUsed extends JingleS5BCandidateTransportInfoElement { public static final String ELEMENT = "candidate-used"; public CandidateUsed(String candidateId) { @@ -88,12 +89,15 @@ public abstract class JingleS5BTransportInfo extends JingleContentTransportInfo } } - public static final class CandidateError extends JingleS5BTransportInfo { + + public static final class CandidateError extends JingleS5BTransportInfoElement { + public static final CandidateError INSTANCE = new CandidateError(); public static final String ELEMENT = "candidate-error"; private CandidateError() { + } @Override @@ -120,12 +124,14 @@ public abstract class JingleS5BTransportInfo extends JingleContentTransportInfo } } - public static final class ProxyError extends JingleS5BTransportInfo { + + public static final class ProxyError extends JingleS5BTransportInfoElement { public static final ProxyError INSTANCE = new ProxyError(); public static final String ELEMENT = "proxy-error"; private ProxyError() { + } @Override @@ -134,7 +140,7 @@ public abstract class JingleS5BTransportInfo extends JingleContentTransportInfo } @Override - public CharSequence toXML() { + public XmlStringBuilder toXML() { XmlStringBuilder xml = new XmlStringBuilder(); xml.halfOpenElement(this); xml.closeEmptyElement(); diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_s5b/elements/package-info.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/element/package-info.java similarity index 91% rename from smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_s5b/elements/package-info.java rename to smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/element/package-info.java index 2a30922f4..3abe10b33 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_s5b/elements/package-info.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/element/package-info.java @@ -19,4 +19,4 @@ * Smack's API for XEP-0260: Jingle SOCKS5 Bytestreams. * Element classes. */ -package org.jivesoftware.smackx.jingle.transports.jingle_s5b.elements; +package org.jivesoftware.smackx.jingle.transport.jingle_s5b.element; diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_s5b/package-info.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/package-info.java similarity index 92% rename from smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_s5b/package-info.java rename to smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/package-info.java index 4f3ab5356..122da3101 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_s5b/package-info.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/package-info.java @@ -18,4 +18,4 @@ /** * Smack's API for XEP-0260: Jingle SOCKS5 Bytestreams. */ -package org.jivesoftware.smackx.jingle.transports.jingle_s5b; +package org.jivesoftware.smackx.jingle.transport.jingle_s5b; diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_s5b/provider/JingleS5BTransportProvider.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/provider/JingleS5BTransportProvider.java similarity index 57% rename from smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_s5b/provider/JingleS5BTransportProvider.java rename to smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/provider/JingleS5BTransportProvider.java index ad681e9e7..f065cfc01 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_s5b/provider/JingleS5BTransportProvider.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/provider/JingleS5BTransportProvider.java @@ -14,49 +14,50 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jivesoftware.smackx.jingle.transports.jingle_s5b.provider; +package org.jivesoftware.smackx.jingle.transport.jingle_s5b.provider; import static org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream.Mode.tcp; import static org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream.Mode.udp; -import static org.jivesoftware.smackx.jingle.transports.jingle_s5b.elements.JingleS5BTransportCandidate.ATTR_CID; -import static org.jivesoftware.smackx.jingle.transports.jingle_s5b.elements.JingleS5BTransportCandidate.ATTR_HOST; -import static org.jivesoftware.smackx.jingle.transports.jingle_s5b.elements.JingleS5BTransportCandidate.ATTR_JID; -import static org.jivesoftware.smackx.jingle.transports.jingle_s5b.elements.JingleS5BTransportCandidate.ATTR_PORT; -import static org.jivesoftware.smackx.jingle.transports.jingle_s5b.elements.JingleS5BTransportCandidate.ATTR_PRIORITY; -import static org.jivesoftware.smackx.jingle.transports.jingle_s5b.elements.JingleS5BTransportCandidate.ATTR_TYPE; +import static org.jivesoftware.smackx.jingle.transport.jingle_s5b.element.JingleS5BTransportCandidateElement.ATTR_CID; +import static org.jivesoftware.smackx.jingle.transport.jingle_s5b.element.JingleS5BTransportCandidateElement.ATTR_HOST; +import static org.jivesoftware.smackx.jingle.transport.jingle_s5b.element.JingleS5BTransportCandidateElement.ATTR_JID; +import static org.jivesoftware.smackx.jingle.transport.jingle_s5b.element.JingleS5BTransportCandidateElement.ATTR_PORT; +import static org.jivesoftware.smackx.jingle.transport.jingle_s5b.element.JingleS5BTransportCandidateElement.ATTR_PRIORITY; +import static org.jivesoftware.smackx.jingle.transport.jingle_s5b.element.JingleS5BTransportCandidateElement.ATTR_TYPE; import static org.xmlpull.v1.XmlPullParser.END_TAG; import static org.xmlpull.v1.XmlPullParser.START_TAG; -import org.jivesoftware.smackx.jingle.element.JingleContentTransport; +import org.jivesoftware.smackx.jingle.element.JingleContentTransportElement; import org.jivesoftware.smackx.jingle.provider.JingleContentTransportProvider; -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.elements.JingleS5BTransportInfo; -import org.jivesoftware.smackx.jingle.transports.jingle_s5b.elements.JingleS5BTransportInfo.JingleS5BCandidateTransportInfo; +import org.jivesoftware.smackx.jingle.transport.jingle_s5b.JingleS5BTransport; +import org.jivesoftware.smackx.jingle.transport.jingle_s5b.element.JingleS5BTransportCandidateElement; +import org.jivesoftware.smackx.jingle.transport.jingle_s5b.element.JingleS5BTransportElement; +import org.jivesoftware.smackx.jingle.transport.jingle_s5b.element.JingleS5BTransportInfoElement; import org.xmlpull.v1.XmlPullParser; + /** * Provider for JingleSocks5BytestreamTransport elements. */ -public class JingleS5BTransportProvider extends JingleContentTransportProvider { +public class JingleS5BTransportProvider extends JingleContentTransportProvider { @Override - public JingleS5BTransport parse(XmlPullParser parser, int initialDepth) throws Exception { - JingleS5BTransport.Builder builder = JingleS5BTransport.getBuilder(); + public JingleS5BTransportElement parse(XmlPullParser parser, int initialDepth) throws Exception { + JingleS5BTransportElement.Builder builder = JingleS5BTransportElement.getBuilder(); - String streamId = parser.getAttributeValue(null, JingleS5BTransport.ATTR_SID); + String streamId = parser.getAttributeValue(null, JingleS5BTransportElement.ATTR_SID); builder.setStreamId(streamId); - String dstAddr = parser.getAttributeValue(null, JingleS5BTransport.ATTR_DSTADDR); + String dstAddr = parser.getAttributeValue(null, JingleS5BTransportElement.ATTR_DSTADDR); builder.setDestinationAddress(dstAddr); - String mode = parser.getAttributeValue(null, JingleS5BTransport.ATTR_MODE); + String mode = parser.getAttributeValue(null, JingleS5BTransportElement.ATTR_MODE); if (mode != null) { builder.setMode(mode.equals(udp.toString()) ? udp : tcp); } - JingleS5BTransportCandidate.Builder cb; + JingleS5BTransportCandidateElement.Builder cb; outerloop: while (true) { int tag = parser.nextTag(); String name = parser.getName(); @@ -64,8 +65,8 @@ public class JingleS5BTransportProvider extends JingleContentTransportProviderXEP-0260: Jingle SOCKS5 Bytestreams. * Provider classes. */ -package org.jivesoftware.smackx.jingle.transports.jingle_s5b.provider; +package org.jivesoftware.smackx.jingle.transport.jingle_s5b.provider; diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/package-info.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/package-info.java new file mode 100644 index 000000000..068e827fe --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/package-info.java @@ -0,0 +1,22 @@ +/** + * + * Copyright 2017 Florian Schmaus, 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. + */ + +/** + * Smack's API for XEP-0166: Jingle. + * Jingle Transport methods. + */ +package org.jivesoftware.smackx.jingle.transport; 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 deleted file mode 100644 index 75d8797b0..000000000 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/JingleTransportManager.java +++ /dev/null @@ -1,74 +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; - -import org.jivesoftware.smack.ConnectionListener; -import org.jivesoftware.smack.XMPPConnection; -import org.jivesoftware.smackx.jingle.JingleSession; -import org.jivesoftware.smackx.jingle.element.JingleContentTransport; - -/** - * Manager for a JingleTransport method. - * @param JingleContentTransport. - */ -public abstract class JingleTransportManager implements ConnectionListener { - - private final XMPPConnection connection; - - public JingleTransportManager(XMPPConnection connection) { - this.connection = connection; - connection.addConnectionListener(this); - } - - public XMPPConnection getConnection() { - return connection; - } - - public abstract String getNamespace(); - - public abstract JingleTransportSession transportSession(JingleSession jingleSession); - - - @Override - public void connected(XMPPConnection connection) { - } - - @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/JingleTransportSession.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/JingleTransportSession.java deleted file mode 100644 index 0776bc6b2..000000000 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/JingleTransportSession.java +++ /dev/null @@ -1,62 +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; - -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 JingleSession jingleSession; - protected T ourProposal, theirProposal; - - public JingleTransportSession(JingleSession session) { - this.jingleSession = 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.getTransport(); - - if (t != null && t.getNamespace().equals(getNamespace())) { - setTheirProposal(t); - } - } - - public abstract void setTheirProposal(JingleContentTransport transport); - - public abstract void initiateOutgoingSession(JingleTransportInitiationCallback callback); - - public abstract void initiateIncomingSession(JingleTransportInitiationCallback callback); - - public abstract String getNamespace(); - - public abstract IQ handleTransportInfo(Jingle transportInfo); - - 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 deleted file mode 100644 index 1c52512ec..000000000 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_ibb/JingleIBBTransportManager.java +++ /dev/null @@ -1,64 +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.jingle_ibb; - -import java.util.WeakHashMap; - -import org.jivesoftware.smack.XMPPConnection; -import org.jivesoftware.smackx.jingle.JingleSession; -import org.jivesoftware.smackx.jingle.provider.JingleContentProviderManager; -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; - -/** - * Manager for Jingle InBandBytestream transports (XEP-0261). - */ -public final class JingleIBBTransportManager extends JingleTransportManager { - - private static final WeakHashMap INSTANCES = new WeakHashMap<>(); - - private JingleIBBTransportManager(XMPPConnection connection) { - super(connection); - JingleContentProviderManager.addJingleContentTransportProvider(getNamespace(), new JingleIBBTransportProvider()); - } - - public static JingleIBBTransportManager getInstanceFor(XMPPConnection connection) { - JingleIBBTransportManager manager = INSTANCES.get(connection); - if (manager == null) { - manager = new JingleIBBTransportManager(connection); - INSTANCES.put(connection, manager); - } - return manager; - } - - @Override - public String getNamespace() { - return JingleIBBTransport.NAMESPACE_V1; - } - - @Override - public JingleTransportSession transportSession(JingleSession jingleSession) { - return new JingleIBBTransportSession(jingleSession); - } - - @Override - 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 deleted file mode 100644 index 61efc9e1a..000000000 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_ibb/JingleIBBTransportSession.java +++ /dev/null @@ -1,115 +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.jingle_ibb; - -import java.util.logging.Level; -import java.util.logging.Logger; - -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.element.JingleContentTransport; -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 static final Logger LOGGER = Logger.getLogger(JingleIBBTransportSession.class.getName()); - - private final JingleIBBTransportManager transportManager; - - public JingleIBBTransportSession(JingleSession session) { - super(session); - transportManager = JingleIBBTransportManager.getInstanceFor(session.getConnection()); - } - - @Override - public JingleIBBTransport createTransport() { - - if (theirProposal == null) { - return new JingleIBBTransport(); - } else { - return new JingleIBBTransport(theirProposal.getBlockSize(), theirProposal.getSessionId()); - } - - } - - @Override - public void setTheirProposal(JingleContentTransport transport) { - theirProposal = (JingleIBBTransport) transport; - } - - @Override - public void initiateOutgoingSession(JingleTransportInitiationCallback callback) { - LOGGER.log(Level.INFO, "Initiate Jingle InBandBytestream session."); - - BytestreamSession session; - try { - session = InBandBytestreamManager.getByteStreamManager(jingleSession.getConnection()) - .establishSession(jingleSession.getRemote(), theirProposal.getSessionId()); - callback.onSessionInitiated(session); - } catch (SmackException.NoResponseException | InterruptedException | SmackException.NotConnectedException | XMPPException.XMPPErrorException e) { - callback.onException(e); - } - } - - @Override - public void initiateIncomingSession(final JingleTransportInitiationCallback callback) { - LOGGER.log(Level.INFO, "Await Jingle InBandBytestream session."); - - InBandBytestreamManager.getByteStreamManager(jingleSession.getConnection()).addIncomingBytestreamListener(new BytestreamListener() { - @Override - public void incomingBytestreamRequest(BytestreamRequest request) { - if (request.getFrom().asFullJidIfPossible().equals(jingleSession.getRemote()) - && request.getSessionID().equals(theirProposal.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.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 deleted file mode 100644 index 2274aaac7..000000000 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_s5b/JingleS5BTransportManager.java +++ /dev/null @@ -1,234 +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.jingle_s5b; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.WeakHashMap; -import java.util.logging.Level; -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.bytestreams.socks5.Socks5BytestreamManager; -import org.jivesoftware.smackx.bytestreams.socks5.Socks5Proxy; -import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream; -import org.jivesoftware.smackx.jingle.JingleSession; -import org.jivesoftware.smackx.jingle.element.Jingle; -import org.jivesoftware.smackx.jingle.element.JingleAction; -import org.jivesoftware.smackx.jingle.element.JingleContent; -import org.jivesoftware.smackx.jingle.provider.JingleContentProviderManager; -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.provider.JingleS5BTransportProvider; - -import org.jxmpp.jid.FullJid; -import org.jxmpp.jid.Jid; - -/** - * Manager for Jingle SOCKS5 Bytestream transports (XEP-0261). - */ -public final class JingleS5BTransportManager extends JingleTransportManager { - - private static final Logger LOGGER = Logger.getLogger(JingleS5BTransportManager.class.getName()); - - private static final WeakHashMap INSTANCES = new WeakHashMap<>(); - - private List localStreamHosts = null; - private List availableStreamHosts = null; - - private static boolean useLocalCandidates = true; - private static boolean useExternalCandidates = true; - - private JingleS5BTransportManager(XMPPConnection connection) { - super(connection); - JingleContentProviderManager.addJingleContentTransportProvider(getNamespace(), new JingleS5BTransportProvider()); - } - - public static JingleS5BTransportManager getInstanceFor(XMPPConnection connection) { - JingleS5BTransportManager manager = INSTANCES.get(connection); - if (manager == null) { - manager = new JingleS5BTransportManager(connection); - INSTANCES.put(connection, manager); - } - return manager; - } - - @Override - public String getNamespace() { - return JingleS5BTransport.NAMESPACE_V1; - } - - @Override - public JingleTransportSession transportSession(JingleSession jingleSession) { - return new JingleS5BTransportSession(jingleSession); - } - - private List queryAvailableStreamHosts() throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException { - Socks5BytestreamManager s5m = Socks5BytestreamManager.getBytestreamManager(getConnection()); - List proxies = s5m.determineProxies(); - return determineStreamHostInfo(proxies); - } - - 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<>(); - - Iterator iterator = proxies.iterator(); - while (iterator.hasNext()) { - Jid proxy = iterator.next(); - Bytestream request = new Bytestream(); - request.setType(IQ.Type.get); - request.setTo(proxy); - try { - Bytestream response = connection.createStanzaCollectorAndSend(request).nextResultOrThrow(); - streamHosts.addAll(response.getStreamHosts()); - } - catch (Exception e) { - iterator.remove(); - } - } - - return streamHosts; - } - - - @Override - public void authenticated(XMPPConnection connection, boolean resumed) { - if (!resumed) try { - Socks5Proxy socks5Proxy = Socks5Proxy.getSocks5Proxy(); - if (!socks5Proxy.isRunning()) { - socks5Proxy.start(); - } - localStreamHosts = queryLocalStreamHosts(); - availableStreamHosts = queryAvailableStreamHosts(); - } catch (InterruptedException | SmackException.NoResponseException | SmackException.NotConnectedException | XMPPException.XMPPErrorException e) { - LOGGER.log(Level.WARNING, "Could not query available StreamHosts: " + e, e); - } - } - - public Jingle createCandidateUsed(FullJid recipient, FullJid initiator, String sessionId, JingleContent.Senders contentSenders, - JingleContent.Creator contentCreator, String contentName, String streamId, - String candidateId) { - Jingle.Builder jb = Jingle.getBuilder(); - jb.setSessionId(sessionId).setInitiator(initiator).setAction(JingleAction.transport_info); - - JingleContent.Builder cb = JingleContent.getBuilder(); - cb.setName(contentName).setCreator(contentCreator).setSenders(contentSenders); - - JingleS5BTransport.Builder tb = JingleS5BTransport.getBuilder(); - tb.setCandidateUsed(candidateId).setStreamId(streamId); - - Jingle jingle = jb.addJingleContent(cb.setTransport(tb.build()).build()).build(); - jingle.setFrom(getConnection().getUser().asFullJidOrThrow()); - jingle.setTo(recipient); - - return jingle; - } - - public Jingle createCandidateError(FullJid remote, FullJid initiator, String sessionId, JingleContent.Senders senders, JingleContent.Creator creator, String name, String streamId) { - Jingle.Builder jb = Jingle.getBuilder(); - jb.setSessionId(sessionId).setInitiator(initiator).setAction(JingleAction.transport_info); - - JingleContent.Builder cb = JingleContent.getBuilder(); - cb.setName(name).setCreator(creator).setSenders(senders); - - JingleS5BTransport.Builder tb = JingleS5BTransport.getBuilder(); - tb.setCandidateError().setStreamId(streamId); - - Jingle jingle = jb.addJingleContent(cb.setTransport(tb.build()).build()).build(); - jingle.setFrom(getConnection().getUser().asFullJidOrThrow()); - jingle.setTo(remote); - - return jingle; - } - - public Jingle createProxyError(FullJid remote, FullJid initiator, String sessionId, - JingleContent.Senders senders, JingleContent.Creator creator, - String name, String streamId) { - Jingle.Builder jb = Jingle.getBuilder(); - jb.setSessionId(sessionId).setAction(JingleAction.transport_info).setInitiator(initiator); - - JingleContent.Builder cb = JingleContent.getBuilder(); - cb.setSenders(senders).setCreator(creator).setName(name); - - JingleS5BTransport.Builder tb = JingleS5BTransport.getBuilder(); - tb.setStreamId(sessionId).setProxyError().setStreamId(streamId); - - Jingle jingle = jb.addJingleContent(cb.setTransport(tb.build()).build()).build(); - jingle.setTo(remote); - jingle.setFrom(getConnection().getUser().asFullJidOrThrow()); - return jingle; - } - - public Jingle createCandidateActivated(FullJid remote, FullJid initiator, String sessionId, - JingleContent.Senders senders, JingleContent.Creator creator, - String name, String streamId, String candidateId) { - Jingle.Builder jb = Jingle.getBuilder(); - jb.setInitiator(initiator).setSessionId(sessionId).setAction(JingleAction.transport_info); - - JingleContent.Builder cb = JingleContent.getBuilder(); - cb.setName(name).setCreator(creator).setSenders(senders); - - JingleS5BTransport.Builder tb = JingleS5BTransport.getBuilder(); - tb.setStreamId(streamId).setCandidateActivated(candidateId); - - Jingle jingle = jb.addJingleContent(cb.setTransport(tb.build()).build()).build(); - jingle.setFrom(getConnection().getUser().asFullJidOrThrow()); - jingle.setTo(remote); - return jingle; - } - - public static void setUseLocalCandidates(boolean localCandidates) { - JingleS5BTransportManager.useLocalCandidates = localCandidates; - } - - public static void setUseExternalCandidates(boolean externalCandidates) { - JingleS5BTransportManager.useExternalCandidates = externalCandidates; - } - - public static boolean isUseLocalCandidates() { - return useLocalCandidates; - } - - public static boolean isUseExternalCandidates() { - return useExternalCandidates; - } -} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_s5b/JingleS5BTransportSession.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_s5b/JingleS5BTransportSession.java deleted file mode 100644 index a74bc276e..000000000 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_s5b/JingleS5BTransportSession.java +++ /dev/null @@ -1,361 +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.jingle_s5b; - -import java.io.IOException; -import java.net.Socket; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.TimeoutException; -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.jivesoftware.smack.SmackException; -import org.jivesoftware.smack.XMPPException; -import org.jivesoftware.smack.packet.IQ; -import org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamSession; -import org.jivesoftware.smackx.bytestreams.socks5.Socks5Client; -import org.jivesoftware.smackx.bytestreams.socks5.Socks5ClientForInitiator; -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.JingleSession; -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.element.JingleContentTransportCandidate; -import org.jivesoftware.smackx.jingle.transports.JingleTransportInitiationCallback; -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.elements.JingleS5BTransportInfo; - -/** - * Handler that handles Jingle Socks5Bytestream transports (XEP-0260). - */ -public class JingleS5BTransportSession extends JingleTransportSession { - private static final Logger LOGGER = Logger.getLogger(JingleS5BTransportSession.class.getName()); - - private JingleTransportInitiationCallback callback; - - public JingleS5BTransportSession(JingleSession jingleSession) { - super(jingleSession); - } - - private UsedCandidate ourChoice, theirChoice; - - @Override - public JingleS5BTransport createTransport() { - if (ourProposal == null) { - ourProposal = createTransport(JingleManager.randomId(), Bytestream.Mode.tcp); - } - return ourProposal; - } - - @Override - public void setTheirProposal(JingleContentTransport transport) { - theirProposal = (JingleS5BTransport) transport; - } - - public JingleS5BTransport createTransport(String sid, Bytestream.Mode mode) { - JingleS5BTransport.Builder jb = JingleS5BTransport.getBuilder() - .setStreamId(sid).setMode(mode).setDestinationAddress( - Socks5Utils.createDigest(sid, jingleSession.getLocal(), jingleSession.getRemote())); - - //Local host - if (JingleS5BTransportManager.isUseLocalCandidates()) { - for (Bytestream.StreamHost host : transportManager().getLocalStreamHosts()) { - jb.addTransportCandidate(new JingleS5BTransportCandidate(host, 100, JingleS5BTransportCandidate.Type.direct)); - } - } - - List remoteHosts = Collections.emptyList(); - if (JingleS5BTransportManager.isUseExternalCandidates()) { - try { - remoteHosts = transportManager().getAvailableStreamHosts(); - } catch (InterruptedException | XMPPException.XMPPErrorException | SmackException.NotConnectedException | SmackException.NoResponseException e) { - LOGGER.log(Level.WARNING, "Could not determine available StreamHosts.", e); - } - } - - for (Bytestream.StreamHost host : remoteHosts) { - jb.addTransportCandidate(new JingleS5BTransportCandidate(host, 0, JingleS5BTransportCandidate.Type.proxy)); - } - - return jb.build(); - } - - public void setTheirTransport(JingleContentTransport transport) { - theirProposal = (JingleS5BTransport) transport; - } - - @Override - public void initiateOutgoingSession(JingleTransportInitiationCallback callback) { - this.callback = callback; - initiateSession(); - } - - @Override - public void initiateIncomingSession(JingleTransportInitiationCallback callback) { - this.callback = callback; - initiateSession(); - } - - private void initiateSession() { - Socks5Proxy.getSocks5Proxy().addTransfer(createTransport().getDestinationAddress()); - JingleContent content = jingleSession.getContents().get(0); - UsedCandidate usedCandidate = chooseFromProposedCandidates(theirProposal); - if (usedCandidate == null) { - ourChoice = CANDIDATE_FAILURE; - Jingle candidateError = transportManager().createCandidateError( - jingleSession.getRemote(), jingleSession.getInitiator(), jingleSession.getSessionId(), - content.getSenders(), content.getCreator(), content.getName(), theirProposal.getStreamId()); - try { - jingleSession.getConnection().sendStanza(candidateError); - } catch (SmackException.NotConnectedException | InterruptedException e) { - LOGGER.log(Level.WARNING, "Could not send candidate-error.", e); - } - } else { - ourChoice = usedCandidate; - Jingle jingle = transportManager().createCandidateUsed(jingleSession.getRemote(), jingleSession.getInitiator(), jingleSession.getSessionId(), - content.getSenders(), content.getCreator(), content.getName(), theirProposal.getStreamId(), ourChoice.candidate.getCandidateId()); - try { - jingleSession.getConnection().createStanzaCollectorAndSend(jingle) - .nextResultOrThrow(); - } catch (InterruptedException | XMPPException.XMPPErrorException | SmackException.NotConnectedException | SmackException.NoResponseException e) { - LOGGER.log(Level.WARNING, "Could not send candidate-used.", e); - } - } - connectIfReady(); - } - - private UsedCandidate chooseFromProposedCandidates(JingleS5BTransport proposal) { - for (JingleContentTransportCandidate c : proposal.getCandidates()) { - JingleS5BTransportCandidate candidate = (JingleS5BTransportCandidate) c; - - try { - return connectToTheirCandidate(candidate); - } catch (InterruptedException | TimeoutException | XMPPException | SmackException | IOException e) { - LOGGER.log(Level.WARNING, "Could not connect to " + candidate.getHost(), e); - } - } - LOGGER.log(Level.WARNING, "Failed to connect to any candidate."); - return null; - } - - private UsedCandidate connectToTheirCandidate(JingleS5BTransportCandidate candidate) - throws InterruptedException, TimeoutException, SmackException, XMPPException, IOException { - Bytestream.StreamHost streamHost = candidate.getStreamHost(); - String address = streamHost.getAddress(); - Socks5Client socks5Client = new Socks5Client(streamHost, theirProposal.getDestinationAddress()); - Socket socket = socks5Client.getSocket(10 * 1000); - LOGGER.log(Level.INFO, "Connected to their StreamHost " + address + " using dstAddr " - + theirProposal.getDestinationAddress()); - return new UsedCandidate(theirProposal, candidate, socket); - } - - private UsedCandidate connectToOurCandidate(JingleS5BTransportCandidate candidate) - throws InterruptedException, TimeoutException, SmackException, XMPPException, IOException { - Bytestream.StreamHost streamHost = candidate.getStreamHost(); - String address = streamHost.getAddress(); - Socks5ClientForInitiator socks5Client = new Socks5ClientForInitiator( - streamHost, ourProposal.getDestinationAddress(), jingleSession.getConnection(), - ourProposal.getStreamId(), jingleSession.getRemote()); - Socket socket = socks5Client.getSocket(10 * 1000); - LOGGER.log(Level.INFO, "Connected to our StreamHost " + address + " using dstAddr " - + ourProposal.getDestinationAddress()); - return new UsedCandidate(ourProposal, candidate, socket); - } - - @Override - public String getNamespace() { - return JingleS5BTransport.NAMESPACE_V1; - } - - @Override - public IQ handleTransportInfo(Jingle transportInfo) { - JingleS5BTransportInfo info = (JingleS5BTransportInfo) transportInfo.getContents().get(0).getTransport().getInfo(); - - switch (info.getElementName()) { - case JingleS5BTransportInfo.CandidateUsed.ELEMENT: - return handleCandidateUsed(transportInfo); - - case JingleS5BTransportInfo.CandidateActivated.ELEMENT: - return handleCandidateActivate(transportInfo); - - case JingleS5BTransportInfo.CandidateError.ELEMENT: - return handleCandidateError(transportInfo); - - case JingleS5BTransportInfo.ProxyError.ELEMENT: - return handleProxyError(transportInfo); - } - //We should never go here, but lets be gracious... - return IQ.createResultIQ(transportInfo); - } - - public IQ handleCandidateUsed(Jingle jingle) { - JingleS5BTransportInfo info = (JingleS5BTransportInfo) jingle.getContents().get(0).getTransport().getInfo(); - String candidateId = ((JingleS5BTransportInfo.CandidateUsed) info).getCandidateId(); - theirChoice = new UsedCandidate(ourProposal, ourProposal.getCandidate(candidateId), null); - - if (theirChoice.candidate == null) { - /* - TODO: Booooooh illegal candidateId!! Go home!!!!11elf - */ - } - - connectIfReady(); - - return IQ.createResultIQ(jingle); - } - - public IQ handleCandidateActivate(Jingle jingle) { - LOGGER.log(Level.INFO, "handleCandidateActivate"); - Socks5BytestreamSession bs = new Socks5BytestreamSession(ourChoice.socket, - ourChoice.candidate.getJid().asBareJid().equals(jingleSession.getRemote().asBareJid())); - callback.onSessionInitiated(bs); - return IQ.createResultIQ(jingle); - } - - public IQ handleCandidateError(Jingle jingle) { - theirChoice = CANDIDATE_FAILURE; - connectIfReady(); - return IQ.createResultIQ(jingle); - } - - public IQ handleProxyError(Jingle jingle) { - //TODO - return IQ.createResultIQ(jingle); - } - - /** - * Determine, which candidate (ours/theirs) is the nominated one. - * Connect to this candidate. If it is a proxy and it is ours, activate it and connect. - * If its a proxy and it is theirs, wait for activation. - * If it is not a proxy, just connect. - */ - private void connectIfReady() { - JingleContent content = jingleSession.getContents().get(0); - if (ourChoice == null || theirChoice == null) { - // Not yet ready. - LOGGER.log(Level.INFO, "Not ready."); - return; - } - - if (ourChoice == CANDIDATE_FAILURE && theirChoice == CANDIDATE_FAILURE) { - LOGGER.log(Level.INFO, "Failure."); - jingleSession.onTransportMethodFailed(getNamespace()); - return; - } - - LOGGER.log(Level.INFO, "Ready."); - - //Determine nominated candidate. - UsedCandidate nominated; - if (ourChoice != CANDIDATE_FAILURE && theirChoice != CANDIDATE_FAILURE) { - if (ourChoice.candidate.getPriority() > theirChoice.candidate.getPriority()) { - nominated = ourChoice; - } else if (ourChoice.candidate.getPriority() < theirChoice.candidate.getPriority()) { - nominated = theirChoice; - } else { - nominated = jingleSession.isInitiator() ? ourChoice : theirChoice; - } - } else if (ourChoice != CANDIDATE_FAILURE) { - nominated = ourChoice; - } else { - nominated = theirChoice; - } - - if (nominated == theirChoice) { - LOGGER.log(Level.INFO, "Their choice, so our proposed candidate is used."); - boolean isProxy = nominated.candidate.getType() == JingleS5BTransportCandidate.Type.proxy; - try { - nominated = connectToOurCandidate(nominated.candidate); - } catch (InterruptedException | IOException | XMPPException | SmackException | TimeoutException e) { - LOGGER.log(Level.INFO, "Could not connect to our candidate.", e); - //TODO: Proxy-Error - return; - } - - if (isProxy) { - LOGGER.log(Level.INFO, "Is external proxy. Activate it."); - Bytestream activate = new Bytestream(ourProposal.getStreamId()); - activate.setMode(null); - activate.setType(IQ.Type.set); - activate.setTo(nominated.candidate.getJid()); - activate.setToActivate(jingleSession.getRemote()); - activate.setFrom(jingleSession.getLocal()); - try { - jingleSession.getConnection().createStanzaCollectorAndSend(activate).nextResultOrThrow(); - } catch (InterruptedException | XMPPException.XMPPErrorException | SmackException.NotConnectedException | SmackException.NoResponseException e) { - LOGGER.log(Level.WARNING, "Could not activate proxy.", e); - return; - } - - LOGGER.log(Level.INFO, "Send candidate-activate."); - Jingle candidateActivate = transportManager().createCandidateActivated( - jingleSession.getRemote(), jingleSession.getInitiator(), jingleSession.getSessionId(), - content.getSenders(), content.getCreator(), content.getName(), nominated.transport.getStreamId(), - nominated.candidate.getCandidateId()); - try { - jingleSession.getConnection().createStanzaCollectorAndSend(candidateActivate) - .nextResultOrThrow(); - } catch (InterruptedException | XMPPException.XMPPErrorException | SmackException.NotConnectedException | SmackException.NoResponseException e) { - LOGGER.log(Level.WARNING, "Could not send candidate-activated", e); - return; - } - } - - LOGGER.log(Level.INFO, "Start transmission."); - Socks5BytestreamSession bs = new Socks5BytestreamSession(nominated.socket, !isProxy); - callback.onSessionInitiated(bs); - - } - //Our choice - else { - LOGGER.log(Level.INFO, "Our choice, so their candidate was used."); - boolean isProxy = nominated.candidate.getType() == JingleS5BTransportCandidate.Type.proxy; - if (!isProxy) { - LOGGER.log(Level.INFO, "Direct connection."); - Socks5BytestreamSession bs = new Socks5BytestreamSession(nominated.socket, true); - callback.onSessionInitiated(bs); - } else { - LOGGER.log(Level.INFO, "Our choice was their external proxy. wait for candidate-activate."); - } - } - } - - @Override - public JingleS5BTransportManager transportManager() { - return JingleS5BTransportManager.getInstanceFor(jingleSession.getConnection()); - } - - private static class UsedCandidate { - private final Socket socket; - private final JingleS5BTransport transport; - private final JingleS5BTransportCandidate candidate; - - public UsedCandidate(JingleS5BTransport transport, JingleS5BTransportCandidate candidate, Socket socket) { - this.socket = socket; - this.transport = transport; - this.candidate = candidate; - } - } - - private static final UsedCandidate CANDIDATE_FAILURE = new UsedCandidate(null, null, null); -} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/FullJidAndSessionId.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/util/FullJidAndSessionId.java similarity index 97% rename from smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/FullJidAndSessionId.java rename to smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/util/FullJidAndSessionId.java index 2bd3e7cde..2cf4baeeb 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/FullJidAndSessionId.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/util/FullJidAndSessionId.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jivesoftware.smackx.jingle; +package org.jivesoftware.smackx.jingle.util; import org.jxmpp.jid.FullJid; diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/Role.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/util/Role.java similarity index 93% rename from smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/Role.java rename to smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/util/Role.java index 0473b0894..75a6f6dc8 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/Role.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/util/Role.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jivesoftware.smackx.jingle; +package org.jivesoftware.smackx.jingle.util; public enum Role { initiator, diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/util/package-info.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/util/package-info.java new file mode 100644 index 000000000..4be0f057f --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/util/package-info.java @@ -0,0 +1,22 @@ +/** + * + * Copyright 2017 Florian Schmaus, 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. + */ + +/** + * Smack's API for XEP-0166: Jingle. + * Small classes with no real place. + */ +package org.jivesoftware.smackx.jingle.util; diff --git a/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/FullJidAndSessionIdTest.java b/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/FullJidAndSessionIdTest.java new file mode 100644 index 000000000..efd4e18bf --- /dev/null +++ b/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/FullJidAndSessionIdTest.java @@ -0,0 +1,48 @@ +/** + * + * 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 static junit.framework.TestCase.assertEquals; +import static junit.framework.TestCase.assertNotSame; +import static junit.framework.TestCase.assertTrue; + +import org.jivesoftware.smack.test.util.SmackTestSuite; +import org.jivesoftware.smackx.jingle.util.FullJidAndSessionId; + +import org.junit.Test; +import org.jxmpp.jid.FullJid; +import org.jxmpp.jid.impl.JidCreate; +import org.jxmpp.stringprep.XmppStringprepException; + +public class FullJidAndSessionIdTest extends SmackTestSuite { + + @Test + public void equalityTest() throws XmppStringprepException { + FullJid albert = JidCreate.fullFrom("albert@einstein.emc/squared"); + String albertId = "10121922"; + FullJidAndSessionId fns = new FullJidAndSessionId(albert, albertId); + + assertEquals("10121922", fns.getSessionId()); + assertEquals(JidCreate.fullFrom("albert@einstein.emc/squared"), fns.getFullJid()); + + FullJidAndSessionId fns2 = new FullJidAndSessionId(JidCreate.fullFrom("albert@einstein.emc/squared"), "10121922"); + assertTrue(fns.equals(fns2)); + assertEquals(fns.hashCode(), fns2.hashCode()); + + assertNotSame(fns, new FullJidAndSessionId(JidCreate.fullFrom("albert@einstein.emc/squared"), "11111111")); + } +} diff --git a/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/JingleContentElementTest.java b/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/JingleContentElementTest.java new file mode 100644 index 000000000..17a4daf0f --- /dev/null +++ b/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/JingleContentElementTest.java @@ -0,0 +1,160 @@ +/** + * + * 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 static junit.framework.TestCase.assertEquals; +import static junit.framework.TestCase.assertNotNull; +import static junit.framework.TestCase.assertNotSame; +import static junit.framework.TestCase.assertNull; +import static junit.framework.TestCase.assertTrue; +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import java.util.Date; + +import org.jivesoftware.smack.DummyConnection; +import org.jivesoftware.smack.SmackException; +import org.jivesoftware.smack.XMPPConnection; +import org.jivesoftware.smack.packet.IQ; +import org.jivesoftware.smack.packet.TestIQ; +import org.jivesoftware.smack.packet.XMPPError; +import org.jivesoftware.smack.test.util.SmackTestSuite; +import org.jivesoftware.smackx.jingle.component.JingleContent; +import org.jivesoftware.smackx.jingle.component.JingleSession; +import org.jivesoftware.smackx.jingle.component.JingleTransport; +import org.jivesoftware.smackx.jingle.element.JingleAction; +import org.jivesoftware.smackx.jingle.element.JingleContentElement; +import org.jivesoftware.smackx.jingle.element.JingleElement; +import org.jivesoftware.smackx.jingle.util.Role; + +import org.junit.Test; +import org.jxmpp.jid.impl.JidCreate; +import org.jxmpp.stringprep.XmppStringprepException; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +/** + * Test the JingleContent class. + */ +public class JingleContentElementTest extends SmackTestSuite { + + @Test(expected = NullPointerException.class) + public void emptyBuilderThrowsTest() { + JingleContentElement.Builder builder = JingleContentElement.getBuilder(); + builder.build(); + } + + @Test(expected = IllegalArgumentException.class) + public void onlyCreatorBuilderThrowsTest() { + JingleContentElement.Builder builder = JingleContentElement.getBuilder(); + builder.setCreator(JingleContentElement.Creator.initiator); + builder.build(); + } + + @Test + public void parserTest() throws Exception { + + JingleContentElement.Builder builder = JingleContentElement.getBuilder(); + + builder.setCreator(JingleContentElement.Creator.initiator); + builder.setName("A name"); + + JingleContentElement content = builder.build(); + assertNotNull(content); + assertNull(content.getDescription()); + assertEquals(JingleContentElement.Creator.initiator, content.getCreator()); + assertEquals("A name", content.getName()); + + builder.setSenders(JingleContentElement.Senders.both); + content = builder.build(); + assertEquals(JingleContentElement.Senders.both, content.getSenders()); + + builder.setDisposition("session"); + JingleContentElement content1 = builder.build(); + assertEquals("session", content1.getDisposition()); + assertNotSame(content.toXML().toString(), content1.toXML().toString()); + assertEquals(content1.toXML().toString(), builder.build().toXML().toString()); + + String xml = + "" + + ""; + assertEquals(xml, content1.toXML().toString()); + + JingleContent fromElement = JingleContent.fromElement(content1); + assertEquals("A name", fromElement.getName()); + assertEquals(content1.getCreator(), fromElement.getCreator()); + assertEquals(content1.getSenders(), fromElement.getSenders()); + assertNull(fromElement.getTransport()); + assertNull(fromElement.getDescription()); + assertNull(fromElement.getSecurity()); + assertXMLEqual(xml, fromElement.getElement().toXML().toString()); + } + + @Test + public void handleJingleRequestTest() { + XMPPConnection connection = mock(XMPPConnection.class); + JingleContent content = new JingleContent(JingleContentElement.Creator.initiator, JingleContentElement.Senders.initiator); + + IQ descriptionInfoResult = new TestIQ("description_info", "test"); + IQ securityInfoResult = new TestIQ("description_info", "test"); + IQ sessionInfoResult = new TestIQ("session_info", "test"); + IQ transportAcceptResult = new TestIQ("transport_accept", "test"); + IQ transportInfoResult = new TestIQ("transport_info", "test"); + IQ transportRejectResult = new TestIQ("transport_reject", "test"); + IQ transportReplaceResult = new TestIQ("transport_replace", "test"); + + JingleElement contentModify = JingleElement.getBuilder().setAction(JingleAction.content_modify).setSessionId("session").build(); + assertTrue(content.handleJingleRequest(contentModify, connection).getError().getCondition() == XMPPError.Condition.feature_not_implemented); + + JingleElement descriptionInfo = JingleElement.getBuilder().setAction(JingleAction.description_info).setSessionId("session").build(); + assertTrue(content.handleJingleRequest(descriptionInfo, connection).getError().getCondition() == XMPPError.Condition.feature_not_implemented); + } + + @Test + public void startTest() throws XmppStringprepException, SmackException.NotConnectedException, InterruptedException { + XMPPConnection connection = new DummyConnection(); + JingleSession session = new JingleSession(JingleManager.getInstanceFor(connection), connection.getUser().asFullJidOrThrow(), JidCreate.fullFrom("bob@baumeister.de/buddl"), Role.initiator, "session"); + JingleContent content = new JingleContent(JingleContentElement.Creator.initiator, JingleContentElement.Senders.initiator); + JingleTransport transport = mock(JingleTransport.class); + content.setTransport(transport); + session.addContent(content); + + final boolean[] sync = new boolean[1]; + + content.start(connection); + doAnswer(new Answer() { + @Override + public Void answer(InvocationOnMock invocation) throws Throwable { + sync[0] = true; + return null; + } + }).when(transport).establishOutgoingBytestreamSession(connection, content, session); + + Date start = new Date(); + while (!sync[0]) { + Date now = new Date(); + if (now.getTime() - start.getTime() > 2000) { + break; + } + //Unfortunately there are no ResultSyncPoints available, so we have to cheat a little bit. + } + + verify(transport).establishOutgoingBytestreamSession(connection, content, session); + } +} diff --git a/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/JingleContentTest.java b/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/JingleContentTest.java deleted file mode 100644 index bd1a430a8..000000000 --- a/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/JingleContentTest.java +++ /dev/null @@ -1,76 +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; - -import static junit.framework.TestCase.assertEquals; -import static junit.framework.TestCase.assertNotNull; -import static junit.framework.TestCase.assertNotSame; -import static junit.framework.TestCase.assertNull; - -import org.jivesoftware.smack.test.util.SmackTestSuite; -import org.jivesoftware.smackx.jingle.element.JingleContent; - -import org.junit.Test; - -/** - * Test the JingleContent class. - */ -public class JingleContentTest extends SmackTestSuite { - - @Test(expected = NullPointerException.class) - public void emptyBuilderThrowsTest() { - JingleContent.Builder builder = JingleContent.getBuilder(); - builder.build(); - } - - @Test(expected = IllegalArgumentException.class) - public void onlyCreatorBuilderThrowsTest() { - JingleContent.Builder builder = JingleContent.getBuilder(); - builder.setCreator(JingleContent.Creator.initiator); - builder.build(); - } - - @Test - public void parserTest() throws Exception { - - JingleContent.Builder builder = JingleContent.getBuilder(); - - builder.setCreator(JingleContent.Creator.initiator); - builder.setName("A name"); - - JingleContent content = builder.build(); - assertNotNull(content); - assertNull(content.getDescription()); - assertEquals(JingleContent.Creator.initiator, content.getCreator()); - assertEquals("A name", content.getName()); - - builder.setSenders(JingleContent.Senders.both); - content = builder.build(); - assertEquals(JingleContent.Senders.both, content.getSenders()); - - builder.setDisposition("session"); - JingleContent content1 = builder.build(); - assertEquals("session", content1.getDisposition()); - assertNotSame(content.toXML().toString(), content1.toXML().toString()); - assertEquals(content1.toXML().toString(), builder.build().toXML().toString()); - - String xml = - "" + - ""; - assertEquals(xml, content1.toXML().toString()); - } -} diff --git a/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/JingleElementTest.java b/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/JingleElementTest.java new file mode 100644 index 000000000..09a9a2d49 --- /dev/null +++ b/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/JingleElementTest.java @@ -0,0 +1,447 @@ +/** + * + * 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 static junit.framework.TestCase.assertEquals; +import static junit.framework.TestCase.assertNotNull; +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; + +import java.io.IOException; + +import org.jivesoftware.smack.DummyConnection; +import org.jivesoftware.smack.XMPPConnection; +import org.jivesoftware.smack.packet.IQ; +import org.jivesoftware.smack.test.util.SmackTestSuite; +import org.jivesoftware.smack.test.util.TestUtils; +import org.jivesoftware.smackx.jingle.element.JingleAction; +import org.jivesoftware.smackx.jingle.element.JingleContentElement; +import org.jivesoftware.smackx.jingle.element.JingleElement; +import org.jivesoftware.smackx.jingle.element.JingleReasonElement; +import org.jivesoftware.smackx.jingle.provider.JingleProvider; +import org.jivesoftware.smackx.jingle.transport.jingle_ibb.JingleIBBTransport; +import org.jivesoftware.smackx.jingle.transport.jingle_ibb.element.JingleIBBTransportElement; + +import org.junit.Before; +import org.junit.Test; +import org.jxmpp.jid.FullJid; +import org.jxmpp.jid.impl.JidCreate; +import org.jxmpp.stringprep.XmppStringprepException; +import org.xml.sax.SAXException; + +/** + * Test the JingleUtil class. + */ +public class JingleElementTest extends SmackTestSuite { + + private FullJid romeo; + private FullJid juliet; + + @Before + public void setup() throws XmppStringprepException { + + XMPPConnection connection = new DummyConnection( + DummyConnection.getDummyConfigurationBuilder() + .setUsernameAndPassword("romeo@montague.lit", + "iluvJulibabe13").build()); + JingleManager jm = JingleManager.getInstanceFor(connection); + romeo = connection.getUser().asFullJidOrThrow(); + juliet = JidCreate.fullFrom("juliet@capulet.lit/balcony"); + } + + @Test + public void createSessionTerminateDeclineTest() throws Exception { + JingleElement terminate = JingleElement.createSessionTerminate(juliet, "thisismadness", JingleReasonElement.Reason.decline); + String jingleXML = + "" + + "" + + "" + + "" + + ""; + String xml = getIQXML(romeo, juliet, terminate.getStanzaId(), jingleXML); + assertXMLEqual(xml, terminate.toXML().toString()); + JingleElement jingle = new JingleProvider().parse(TestUtils.getParser(jingleXML)); + assertNotNull(jingle); + assertEquals(jingle.getAction(), JingleAction.session_terminate); + assertEquals(jingle.getReason().asEnum(), JingleReasonElement.Reason.decline); + } + + @Test + public void createSessionTerminateSuccessTest() throws Exception { + JingleElement success = JingleElement.createSessionTerminate(juliet, "thisissparta", JingleReasonElement.Reason.success); + String jingleXML = + "" + + "" + + "" + + "" + + ""; + String xml = getIQXML(romeo, juliet, success.getStanzaId(), jingleXML); + assertXMLEqual(xml, success.toXML().toString()); + JingleElement jingle = new JingleProvider().parse(TestUtils.getParser(jingleXML)); + assertNotNull(jingle); + assertEquals(jingle.getAction(), JingleAction.session_terminate); + assertEquals(jingle.getReason().asEnum(), JingleReasonElement.Reason.success); + } + + @Test + public void createSessionTerminateBusyTest() throws Exception { + JingleElement busy = JingleElement.createSessionTerminate(juliet, "thisispatrick", JingleReasonElement.Reason.busy); + String jingleXML = + "" + + "" + + "" + + "" + + ""; + String xml = getIQXML(romeo, juliet, busy.getStanzaId(), jingleXML); + assertXMLEqual(xml, busy.toXML().toString()); + JingleElement jingle = new JingleProvider().parse(TestUtils.getParser(jingleXML)); + assertNotNull(jingle); + assertEquals(jingle.getAction(), JingleAction.session_terminate); + assertEquals(jingle.getReason().asEnum(), JingleReasonElement.Reason.busy); + } + + @Test + public void createSessionTerminateAlternativeSessionTest() throws Exception { + JingleElement busy = JingleElement.createSessionTerminate(juliet, "thisistherhythm", JingleReasonElement.AlternativeSession("ofthenight")); + String jingleXML = + "" + + "" + + "" + + "ofthenight" + + "" + + "" + + ""; + String xml = getIQXML(romeo, juliet, busy.getStanzaId(), jingleXML); + assertXMLEqual(xml, busy.toXML().toString()); + JingleElement jingle = new JingleProvider().parse(TestUtils.getParser(jingleXML)); + assertNotNull(jingle); + assertEquals(jingle.getAction(), JingleAction.session_terminate); + assertEquals(jingle.getReason().asEnum(), JingleReasonElement.Reason.alternative_session); + JingleReasonElement.AlternativeSession alt = (JingleReasonElement.AlternativeSession) jingle.getReason(); + assertEquals("ofthenight", alt.getAlternativeSessionId()); + } + + @Test + public void createSessionTerminateCancelTest() throws Exception { + JingleElement cancel = JingleElement.createSessionTerminate(juliet, "thisistheend", JingleReasonElement.Reason.cancel); + String jingleXML = + "" + + "" + + "" + + "" + + ""; + String xml = getIQXML(romeo, juliet, cancel.getStanzaId(), jingleXML); + assertXMLEqual(xml, cancel.toXML().toString()); + JingleElement jingle = new JingleProvider().parse(TestUtils.getParser(jingleXML)); + assertNotNull(jingle); + assertEquals(jingle.getAction(), JingleAction.session_terminate); + assertEquals(jingle.getReason().asEnum(), JingleReasonElement.Reason.cancel); + } + + @Test + public void createSessionTerminateUnsupportedTransportsTest() throws Exception { + JingleElement unsupportedTransports = JingleElement.createSessionTerminate(juliet, "thisisus", JingleReasonElement.Reason.unsupported_transports); + String jingleXML = + "" + + "" + + "" + + "" + + ""; + String xml = getIQXML(romeo, juliet, unsupportedTransports.getStanzaId(), jingleXML); + assertXMLEqual(xml, unsupportedTransports.toXML().toString()); + JingleElement jingle = new JingleProvider().parse(TestUtils.getParser(jingleXML)); + assertNotNull(jingle); + assertEquals(jingle.getAction(), JingleAction.session_terminate); + assertEquals(jingle.getReason().asEnum(), JingleReasonElement.Reason.unsupported_transports); + } + + @Test + public void createSessionTerminateUnsupportedApplicationsTest() throws Exception { + JingleElement unsupportedApplications = JingleElement.createSessionTerminate(juliet, "thisiswar", JingleReasonElement.Reason.unsupported_applications); + String jingleXML = + "" + + "" + + "" + + "" + + ""; + String xml = getIQXML(romeo, juliet, unsupportedApplications.getStanzaId(), jingleXML); + assertXMLEqual(xml, unsupportedApplications.toXML().toString()); + JingleElement jingle = new JingleProvider().parse(TestUtils.getParser(jingleXML)); + assertNotNull(jingle); + assertEquals(jingle.getAction(), JingleAction.session_terminate); + assertEquals(jingle.getReason().asEnum(), JingleReasonElement.Reason.unsupported_applications); + } + + @Test + public void createSessionTerminateFailedTransportTest() throws IOException, SAXException { + JingleElement failedTransport = JingleElement.createSessionTerminate(juliet, "derailed", JingleReasonElement.Reason.failed_transport); + String jingleXML = + "" + + "" + + "" + + "" + + ""; + String xml = getIQXML(romeo, juliet, failedTransport.getStanzaId(), jingleXML); + assertXMLEqual(xml, failedTransport.toXML().toString()); + assertEquals(JingleAction.session_terminate, failedTransport.getAction()); + assertEquals(JingleReasonElement.Reason.failed_transport, failedTransport.getReason().asEnum()); + } + + @Test + public void createSessionTerminateFailedApplicationTest() throws IOException, SAXException { + JingleElement failedApplication = JingleElement.createSessionTerminate(juliet, "crashed", JingleReasonElement.Reason.failed_application); + String jingleXML = + "" + + "" + + "" + + "" + + ""; + String xml = getIQXML(romeo, juliet, failedApplication.getStanzaId(), jingleXML); + assertXMLEqual(xml, failedApplication.toXML().toString()); + assertEquals(JingleAction.session_terminate, failedApplication.getAction()); + assertEquals(JingleReasonElement.Reason.failed_application, failedApplication.getReason().asEnum()); + } + + @Test + public void createSessionPingTest() throws Exception { + JingleElement ping = JingleElement.createSessionPing(juliet, "thisisit"); + String jingleXML = + ""; + String xml = getIQXML(romeo, juliet, ping.getStanzaId(), jingleXML); + assertXMLEqual(xml, ping.toXML().toString()); + JingleElement jingle = new JingleProvider().parse(TestUtils.getParser(jingleXML)); + assertNotNull(jingle); + assertEquals(JingleAction.session_info, jingle.getAction()); + } + + @Test + public void createSessionTerminateContentCancelTest() throws Exception { + JingleElement cancel = JingleElement.createSessionTerminateContentCancel(juliet, "thisismumbo#5", JingleContentElement.Creator.initiator, "content123"); + String jingleXML = + "" + + "" + + "" + + "" + + "" + + ""; + String xml = getIQXML(romeo, juliet, cancel.getStanzaId(), jingleXML); + assertXMLEqual(xml, cancel.toXML().toString()); + JingleElement jingle = new JingleProvider().parse(TestUtils.getParser(jingleXML)); + assertNotNull(jingle); + assertEquals(JingleAction.session_terminate, jingle.getAction()); + assertEquals(JingleReasonElement.Reason.cancel, jingle.getReason().asEnum()); + assertEquals("thisismumbo#5", jingle.getSid()); + JingleContentElement content = jingle.getContents().get(0); + assertNotNull(content); + assertEquals("content123", content.getName()); + assertEquals(JingleContentElement.Creator.initiator, content.getCreator()); + } + + @Test + public void createSessionTerminateIncompatibleParameters() throws IOException, SAXException { + JingleElement terminate = JingleElement.createSessionTerminate(juliet, "incompatibleSID", JingleReasonElement.Reason.incompatible_parameters); + String jingleXML = + "" + + "" + + "" + + "" + + ""; + String xml = getIQXML(romeo, juliet, terminate.getStanzaId(), jingleXML); + assertXMLEqual(xml, terminate.toXML().toString()); + assertEquals(JingleReasonElement.Reason.incompatible_parameters, terminate.getReason().asEnum()); + assertEquals("incompatibleSID", terminate.getSid()); + } + + @Test + public void createTransportAcceptTest() throws IOException, SAXException { + JingleElement transportAccept = JingleElement.createTransportAccept(juliet, romeo, "transAcc", JingleContentElement.Creator.initiator, "cname", new JingleIBBTransportElement("transid", JingleIBBTransport.DEFAULT_BLOCK_SIZE)); + String jingleXML = + "" + + "" + + "" + + "" + + ""; + String xml = getIQXML(juliet, romeo, transportAccept.getStanzaId(), jingleXML); + assertXMLEqual(xml, transportAccept.toXML().toString()); + assertEquals(JingleAction.transport_accept, transportAccept.getAction()); + assertEquals("transAcc", transportAccept.getSid()); + } + + @Test + public void createTransportRejectTest() { + //TODO: Find example + } + + @Test + public void createTransportReplaceTest() throws IOException, SAXException { + JingleElement transportReplace = JingleElement.createTransportReplace(juliet, romeo, "transAcc", JingleContentElement.Creator.initiator, "cname", new JingleIBBTransportElement("transid", JingleIBBTransport.DEFAULT_BLOCK_SIZE)); + String jingleXML = + "" + + "" + + "" + + "" + + ""; + String xml = getIQXML(juliet, romeo, transportReplace.getStanzaId(), jingleXML); + assertXMLEqual(xml, transportReplace.toXML().toString()); + assertEquals(JingleAction.transport_replace, transportReplace.getAction()); + assertEquals("transAcc", transportReplace.getSid()); + } + + @Test + public void createErrorMalformedRequestTest() throws Exception { + JingleElement j = defaultJingle(romeo, "error123"); + IQ error = JingleElement.createJingleErrorMalformedRequest(j); + String xml = + "" + + "" + + "" + + "" + + ""; + assertXMLEqual(xml, error.toXML().toString()); + } + + @Test + public void createErrorTieBreakTest() throws IOException, SAXException { + JingleElement j = defaultJingle(romeo, "thisistie"); + IQ error = JingleElement.createJingleErrorTieBreak(j); + String xml = + "" + + "" + + "" + + "" + + "" + + ""; + assertXMLEqual(xml, error.toXML().toString()); + } + + @Test + public void createErrorUnknownSessionTest() throws IOException, SAXException { + JingleElement j = defaultJingle(romeo, "youknownothingjohnsnow"); + IQ error = JingleElement.createJingleErrorUnknownSession(j); + String xml = + "" + + "" + + "" + + "" + + "" + + ""; + assertXMLEqual(xml, error.toXML().toString()); + } + + @Test + public void createErrorUnknownInitiatorTest() throws IOException, SAXException { + JingleElement j = defaultJingle(romeo, "iamyourfather"); + IQ error = JingleElement.createJingleErrorUnknownInitiator(j); + String xml = + "" + + "" + + "" + + "" + + ""; + assertXMLEqual(xml, error.toXML().toString()); + } + + @Test + public void createErrorOutOfOrderTest() throws IOException, SAXException { + JingleElement j = defaultJingle(romeo, "yourfatheriam"); + IQ error = JingleElement.createJingleErrorOutOfOrder(j); + String xml = + "" + + //"" + + "" + //TODO: Why? + "" + + "" + + "" + + ""; + assertXMLEqual(xml, error.toXML().toString()); + } + + @Test + public void createErrorUnsupportedInfoTest() throws IOException, SAXException { + JingleElement j = defaultJingle(romeo, "thisstatementiswrong"); + IQ error = JingleElement.createJingleErrorUnsupportedInfo(j); + String xml = + "" + + "" + + "" + + "" + + "" + + ""; + assertXMLEqual(xml, error.toXML().toString()); + } + + public static String getIQXML(FullJid from, FullJid to, String stanzaId, String jingleXML) { + return "" + + jingleXML + + ""; + } + + private JingleElement defaultJingle(FullJid recipient, String sessionId) { + return JingleElement.createSessionPing(recipient, sessionId); + } +} diff --git a/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/JingleErrorTest.java b/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/JingleErrorElementTest.java similarity index 76% rename from smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/JingleErrorTest.java rename to smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/JingleErrorElementTest.java index 6ca6d88a9..5fdc7bb37 100644 --- a/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/JingleErrorTest.java +++ b/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/JingleErrorElementTest.java @@ -20,7 +20,7 @@ import static junit.framework.TestCase.assertEquals; import org.jivesoftware.smack.test.util.SmackTestSuite; import org.jivesoftware.smack.test.util.TestUtils; -import org.jivesoftware.smackx.jingle.element.JingleError; +import org.jivesoftware.smackx.jingle.element.JingleErrorElement; import org.jivesoftware.smackx.jingle.provider.JingleErrorProvider; import org.junit.Test; @@ -28,39 +28,39 @@ import org.junit.Test; /** * Test the JingleError class. */ -public class JingleErrorTest extends SmackTestSuite { +public class JingleErrorElementTest extends SmackTestSuite { @Test public void tieBreakTest() throws Exception { String xml = ""; - JingleError error = new JingleErrorProvider().parse(TestUtils.getParser(xml)); + JingleErrorElement error = new JingleErrorProvider().parse(TestUtils.getParser(xml)); assertEquals(xml, error.toXML().toString()); } @Test public void unknownSessionTest() throws Exception { String xml = ""; - JingleError error = new JingleErrorProvider().parse(TestUtils.getParser(xml)); + JingleErrorElement error = new JingleErrorProvider().parse(TestUtils.getParser(xml)); assertEquals(xml, error.toXML().toString()); } @Test public void unsupportedInfoTest() throws Exception { String xml = ""; - JingleError error = new JingleErrorProvider().parse(TestUtils.getParser(xml)); + JingleErrorElement error = new JingleErrorProvider().parse(TestUtils.getParser(xml)); assertEquals(xml, error.toXML().toString()); } @Test public void outOfOrderTest() throws Exception { String xml = ""; - JingleError error = new JingleErrorProvider().parse(TestUtils.getParser(xml)); + JingleErrorElement error = new JingleErrorProvider().parse(TestUtils.getParser(xml)); assertEquals(xml, error.toXML().toString()); } @Test(expected = IllegalArgumentException.class) public void illegalArgumentTest() { - JingleError.fromString("inexistent-error"); + JingleErrorElement.fromString("inexistent-error"); } diff --git a/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/JingleReasonTest.java b/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/JingleReasonElementTest.java similarity index 60% rename from smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/JingleReasonTest.java rename to smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/JingleReasonElementTest.java index d62de70b3..a3ccc50af 100644 --- a/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/JingleReasonTest.java +++ b/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/JingleReasonElementTest.java @@ -20,67 +20,67 @@ import static junit.framework.TestCase.assertEquals; import org.jivesoftware.smack.test.util.SmackTestSuite; -import org.jivesoftware.smackx.jingle.element.JingleReason; +import org.jivesoftware.smackx.jingle.element.JingleReasonElement; import org.junit.Test; /** * Test JingleReason functionality. */ -public class JingleReasonTest extends SmackTestSuite { +public class JingleReasonElementTest extends SmackTestSuite { @Test public void parserTest() { assertEquals("", - JingleReason.Success.toXML().toString()); + JingleReasonElement.Success.toXML().toString()); assertEquals("", - JingleReason.Busy.toXML().toString()); + JingleReasonElement.Busy.toXML().toString()); assertEquals("", - JingleReason.Cancel.toXML().toString()); + JingleReasonElement.Cancel.toXML().toString()); assertEquals("", - JingleReason.ConnectivityError.toXML().toString()); + JingleReasonElement.ConnectivityError.toXML().toString()); assertEquals("", - JingleReason.Decline.toXML().toString()); + JingleReasonElement.Decline.toXML().toString()); assertEquals("", - JingleReason.Expired.toXML().toString()); + JingleReasonElement.Expired.toXML().toString()); assertEquals("", - JingleReason.UnsupportedTransports.toXML().toString()); + JingleReasonElement.UnsupportedTransports.toXML().toString()); assertEquals("", - JingleReason.FailedTransport.toXML().toString()); + JingleReasonElement.FailedTransport.toXML().toString()); assertEquals("", - JingleReason.GeneralError.toXML().toString()); + JingleReasonElement.GeneralError.toXML().toString()); assertEquals("", - JingleReason.Gone.toXML().toString()); + JingleReasonElement.Gone.toXML().toString()); assertEquals("", - JingleReason.MediaError.toXML().toString()); + JingleReasonElement.MediaError.toXML().toString()); assertEquals("", - JingleReason.SecurityError.toXML().toString()); + JingleReasonElement.SecurityError.toXML().toString()); assertEquals("", - JingleReason.UnsupportedApplications.toXML().toString()); + JingleReasonElement.UnsupportedApplications.toXML().toString()); assertEquals("", - JingleReason.Timeout.toXML().toString()); + JingleReasonElement.Timeout.toXML().toString()); assertEquals("", - JingleReason.FailedApplication.toXML().toString()); + JingleReasonElement.FailedApplication.toXML().toString()); assertEquals("", - JingleReason.IncompatibleParameters.toXML().toString()); + JingleReasonElement.IncompatibleParameters.toXML().toString()); assertEquals("1234", - JingleReason.AlternativeSession("1234").toXML().toString()); + JingleReasonElement.AlternativeSession("1234").toXML().toString()); } @Test(expected = NullPointerException.class) public void alternativeSessionEmptyStringTest() { // Alternative sessionID must not be empty - JingleReason.AlternativeSession(""); + JingleReasonElement.AlternativeSession(""); } @Test(expected = NullPointerException.class) public void alternativeSessionNullStringTest() { // Alternative sessionID must not be null - JingleReason.AlternativeSession(null); + JingleReasonElement.AlternativeSession(null); } @Test(expected = IllegalArgumentException.class) public void illegalArgumentTest() { - JingleReason.Reason.fromString("illegal-reason"); + JingleReasonElement.Reason.fromString("illegal-reason"); } } diff --git a/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/JingleTest.java b/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/JingleTest.java deleted file mode 100644 index c7827e475..000000000 --- a/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/JingleTest.java +++ /dev/null @@ -1,81 +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; - -import static junit.framework.TestCase.assertEquals; -import static junit.framework.TestCase.assertNotNull; -import static junit.framework.TestCase.assertTrue; - -import org.jivesoftware.smack.test.util.SmackTestSuite; - -import org.jivesoftware.smackx.jingle.element.Jingle; -import org.jivesoftware.smackx.jingle.element.JingleAction; - -import org.junit.Test; -import org.jxmpp.jid.FullJid; -import org.jxmpp.jid.impl.JidCreate; -import org.jxmpp.stringprep.XmppStringprepException; - -/** - * Test the Jingle class. - */ -public class JingleTest extends SmackTestSuite { - - @Test(expected = IllegalArgumentException.class) - public void emptyBuilderTest() { - Jingle.Builder builder = Jingle.getBuilder(); - builder.build(); - } - - @Test(expected = NullPointerException.class) - public void onlySessionIdBuilderTest() { - String sessionId = "testSessionId"; - - Jingle.Builder builder = Jingle.getBuilder(); - builder.setSessionId(sessionId); - builder.build(); - } - - @Test - public void parserTest() throws XmppStringprepException { - String sessionId = "testSessionId"; - - Jingle.Builder builder = Jingle.getBuilder(); - builder.setSessionId(sessionId); - builder.setAction(JingleAction.session_initiate); - - FullJid romeo = JidCreate.fullFrom("romeo@montague.lit/orchard"); - FullJid juliet = JidCreate.fullFrom("juliet@capulet.lit/balcony"); - builder.setInitiator(romeo); - builder.setResponder(juliet); - - Jingle jingle = builder.build(); - assertNotNull(jingle); - assertEquals(romeo, jingle.getInitiator()); - assertEquals(juliet, jingle.getResponder()); - assertEquals(jingle.getAction(), JingleAction.session_initiate); - assertEquals(sessionId, jingle.getSid()); - - String xml = "" + - ""; - assertTrue(jingle.toXML().toString().contains(xml)); - } -} 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 deleted file mode 100644 index 500ee2279..000000000 --- a/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/JingleUtilTest.java +++ /dev/null @@ -1,102 +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; - -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=" + - "" + - "" + - " " + - "" + - "" + - "" + - "" + - "" + - ""; - } -} diff --git a/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/component/JingleContentTest.java b/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/component/JingleContentTest.java new file mode 100644 index 000000000..305f45d41 --- /dev/null +++ b/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/component/JingleContentTest.java @@ -0,0 +1,43 @@ +/** + * + * 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.component; + +import static junit.framework.TestCase.assertEquals; +import static junit.framework.TestCase.assertNotNull; +import static junit.framework.TestCase.assertNull; + +import org.jivesoftware.smack.test.util.SmackTestSuite; +import org.jivesoftware.smackx.jingle.element.JingleContentElement; + +import org.junit.Test; + +public class JingleContentTest extends SmackTestSuite { + + @Test + public void jingleContentTest() { + JingleContent content = new JingleContent(JingleContentElement.Creator.initiator, JingleContentElement.Senders.responder); + assertEquals(JingleContentElement.Creator.initiator, content.getCreator()); + assertEquals(JingleContentElement.Senders.responder, content.getSenders()); + assertNull(content.getDescription()); + assertNull(content.getTransport()); + assertNull(content.getSecurity()); + assertNotNull(content.getName()); //MUST NOT BE NULL! + assertEquals(0, content.getTransportBlacklist().size()); + } + + +} diff --git a/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/component/JingleSessionTest.java b/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/component/JingleSessionTest.java new file mode 100644 index 000000000..641eeec78 --- /dev/null +++ b/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/component/JingleSessionTest.java @@ -0,0 +1,251 @@ +/** + * + * 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.component; + +import static junit.framework.TestCase.assertEquals; +import static junit.framework.TestCase.assertFalse; +import static junit.framework.TestCase.assertNotNull; +import static junit.framework.TestCase.assertNull; +import static junit.framework.TestCase.assertTrue; + +import org.jivesoftware.smack.DummyConnection; +import org.jivesoftware.smack.test.util.SmackTestSuite; +import org.jivesoftware.smackx.bytestreams.BytestreamSession; +import org.jivesoftware.smackx.jingle.JingleManager; +import org.jivesoftware.smackx.jingle.element.JingleAction; +import org.jivesoftware.smackx.jingle.element.JingleContentDescriptionElement; +import org.jivesoftware.smackx.jingle.element.JingleContentDescriptionInfoElement; +import org.jivesoftware.smackx.jingle.element.JingleContentElement; +import org.jivesoftware.smackx.jingle.element.JingleElement; +import org.jivesoftware.smackx.jingle.transport.jingle_ibb.JingleIBBTransport; +import org.jivesoftware.smackx.jingle.transport.jingle_ibb.element.JingleIBBTransportElement; +import org.jivesoftware.smackx.jingle.util.Role; + +import org.junit.Test; +import org.jxmpp.jid.FullJid; +import org.jxmpp.jid.impl.JidCreate; +import org.jxmpp.stringprep.XmppStringprepException; + +public class JingleSessionTest extends SmackTestSuite { + + @Test + public void jingleSessionTest() throws XmppStringprepException { + DummyConnection dummyConnection = new DummyConnection(); + FullJid alice = JidCreate.fullFrom("alice@wonderland.lit/test123"); + FullJid madHatter = JidCreate.fullFrom("mad@hat.net/cat"); + + JingleManager jingleManager = JingleManager.getInstanceFor(dummyConnection); + + JingleSession session = new JingleSession(jingleManager, alice, madHatter, Role.initiator, "WeReAlLmAdHeRe"); + + assertEquals(alice, session.getInitiator()); + assertEquals(madHatter, session.getResponder()); + assertEquals(alice, session.getOurJid()); + assertEquals(madHatter, session.getPeer()); + + assertEquals(0, session.getContents().size()); + assertEquals("WeReAlLmAdHeRe", session.getSessionId()); + assertEquals(jingleManager, session.getJingleManager()); + } + + @Test(expected = IllegalStateException.class) + public void getSoleContentThrowingTest() { + JingleSession session = new JingleSession(JingleManager.getInstanceFor(new DummyConnection()), null, null, Role.initiator, null); + assertTrue(session.isInitiator()); + assertFalse(session.isResponder()); + JingleContent c1 = new JingleContent(JingleContentElement.Creator.initiator, JingleContentElement.Senders.initiator); + JingleContent c2 = new JingleContent(JingleContentElement.Creator.initiator, JingleContentElement.Senders.initiator); + session.addContent(c1); + assertEquals(c1, session.getContent(c1.getName())); + session.addContent(c2); + assertEquals(c2, session.getContent(c2.getName())); + + session.getSoleContentOrThrow(); + } + + @Test + public void getSoleContentTest() { + JingleSession session = new JingleSession(JingleManager.getInstanceFor(new DummyConnection()), null, null, Role.responder, null); + assertTrue(session.isResponder()); + assertFalse(session.isInitiator()); + assertNull(session.getSoleContentOrThrow()); + JingleContent c1 = new JingleContent(JingleContentElement.Creator.initiator, JingleContentElement.Senders.initiator); + assertNull(c1.getParent()); + session.addContent(c1); + assertEquals(session, c1.getParent()); + + assertEquals(c1, session.getSoleContentOrThrow()); + } + + @Test + public void createSessionAcceptTest() throws XmppStringprepException { + FullJid initiator = JidCreate.fullFrom("initiator@server.tld/res"); + FullJid responder = JidCreate.fullFrom("responder@server.tld/res"); + JingleManager manager = JingleManager.getInstanceFor(new DummyConnection()); + JingleSession session = new JingleSession(manager, initiator, responder, Role.initiator, "sessionId"); + + JingleContent content = new JingleContent(JingleContentElement.Creator.initiator, JingleContentElement.Senders.initiator); + + JingleIBBTransport transport = new JingleIBBTransport("streamId", (short) 1024); + content.setTransport(transport); + + JingleDescription description = new JingleDescription() { + public static final String NAMESPACE = "urn:xmpp:jingle:apps:stub:0"; + + @Override + public JingleContentDescriptionElement getElement() { + return new JingleContentDescriptionElement(null) { + @Override + public String getNamespace() { + return NAMESPACE; + } + }; + } + + @Override + public JingleElement handleDescriptionInfo(JingleContentDescriptionInfoElement info) { + return null; + } + + @Override + public void onBytestreamReady(BytestreamSession bytestreamSession) { + + } + + @Override + public String getNamespace() { + return NAMESPACE; + } + }; + content.setDescription(description); + + session.addContent(content); + + JingleElement sessionElement = session.createSessionInitiate(); + assertNotNull(sessionElement); + assertEquals("sessionId", sessionElement.getSid()); + assertEquals(initiator, sessionElement.getInitiator()); + assertNull(sessionElement.getResponder()); + assertEquals(JingleAction.session_initiate, sessionElement.getAction()); + JingleContentElement contentElement = sessionElement.getSoleContentOrThrow(); + assertNotNull(contentElement); + assertEquals(content.getName(), contentElement.getName()); + assertEquals(content.getCreator(), contentElement.getCreator()); + assertEquals(content.getSenders(), contentElement.getSenders()); + assertEquals(0, content.getTransportBlacklist().size()); + assertEquals(content.getElement().toXML().toString(), contentElement.toXML().toString()); + + JingleIBBTransportElement transportElement = (JingleIBBTransportElement) contentElement.getTransport(); + assertNotNull(transportElement); + assertEquals(transport.getBlockSize(), transportElement.getBlockSize()); + assertEquals(transport.getStreamId(), transportElement.getStreamId()); + assertEquals(transport.getNamespace(), transportElement.getNamespace()); + assertEquals(transport.getElement().toXML().toString(), transportElement.toXML().toString()); + + JingleContentDescriptionElement descriptionElement = contentElement.getDescription(); + assertNotNull(descriptionElement); + assertEquals(description.getNamespace(), descriptionElement.getNamespace()); + assertEquals(description.getElement().toXML().toString(), descriptionElement.toXML().toString()); + + assertNull(contentElement.getSecurity()); + assertTrue(content.isSending()); + assertFalse(content.isReceiving()); + } + + @Test(expected = IllegalArgumentException.class) + public void duplicateContentAddTest() throws XmppStringprepException { + FullJid initiator = JidCreate.fullFrom("initiator@server.tld/res"); + FullJid responder = JidCreate.fullFrom("responder@server.tld/res"); + JingleManager manager = JingleManager.getInstanceFor(new DummyConnection()); + JingleSession session = new JingleSession(manager, initiator, responder, Role.initiator, "sessionId"); + + JingleContent content1 = new JingleContent(JingleContentElement.Creator.initiator, JingleContentElement.Senders.initiator); + JingleContent content2 = new JingleContent(null, null, null, content1.getName(), null, JingleContentElement.Creator.initiator, JingleContentElement.Senders.initiator); + + session.addContent(content1); + session.addContent(content2); + } + + @Test(expected = IllegalStateException.class) + public void sessionInitiateThrowsAsResponderTest() { + JingleSession session = new JingleSession(JingleManager.getInstanceFor(new DummyConnection()), + null, null, Role.responder, "session"); + session.createSessionInitiate(); + } + + @Test + public void sessionAcceptTest() throws XmppStringprepException { + FullJid initiator = JidCreate.fullFrom("initiator@server.tld/res"); + FullJid responder = JidCreate.fullFrom("responder@server.tld/res"); + JingleManager manager = JingleManager.getInstanceFor(new DummyConnection()); + JingleSession session = new JingleSession(manager, initiator, responder, Role.responder, "sessionId"); + + JingleContent content = new JingleContent(JingleContentElement.Creator.initiator, JingleContentElement.Senders.initiator); + + JingleIBBTransport transport = new JingleIBBTransport("streamId", (short) 1024); + content.setTransport(transport); + + JingleDescription description = new JingleDescription() { + public static final String NAMESPACE = "urn:xmpp:jingle:apps:stub:0"; + + @Override + public JingleContentDescriptionElement getElement() { + return new JingleContentDescriptionElement(null) { + @Override + public String getNamespace() { + return NAMESPACE; + } + }; + } + + @Override + public JingleElement handleDescriptionInfo(JingleContentDescriptionInfoElement info) { + return null; + } + + @Override + public void onBytestreamReady(BytestreamSession bytestreamSession) { + + } + + @Override + public String getNamespace() { + return NAMESPACE; + } + }; + content.setDescription(description); + + session.addContent(content); + + JingleElement accept = session.createSessionAccept(); + assertNotNull(accept); + assertEquals(JingleAction.session_accept, accept.getAction()); + assertNull(accept.getInitiator()); + assertEquals(session.getResponder(), accept.getResponder()); + assertEquals(1, accept.getContents().size()); + assertEquals(content.getName(), accept.getSoleContentOrThrow().getName()); + assertFalse(content.isSending()); + assertTrue(content.isReceiving()); + } + + @Test(expected = IllegalStateException.class) + public void sessionAcceptThrowsAsInitiatorTest() { + JingleSession session = new JingleSession(JingleManager.getInstanceFor(new DummyConnection()), + null, null, Role.initiator, "session"); + session.createSessionAccept(); + } +} diff --git a/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/provider/JingleContentProviderManagerTest.java b/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/provider/JingleContentProviderManagerTest.java index 4655a621b..af08ebbf1 100644 --- a/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/provider/JingleContentProviderManagerTest.java +++ b/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/provider/JingleContentProviderManagerTest.java @@ -20,10 +20,11 @@ import static junit.framework.TestCase.assertEquals; import static junit.framework.TestCase.assertNull; import org.jivesoftware.smack.test.util.SmackTestSuite; -import org.jivesoftware.smackx.jingle.transports.jingle_ibb.element.JingleIBBTransport; -import org.jivesoftware.smackx.jingle.transports.jingle_ibb.provider.JingleIBBTransportProvider; -import org.jivesoftware.smackx.jingle.transports.jingle_s5b.elements.JingleS5BTransport; -import org.jivesoftware.smackx.jingle.transports.jingle_s5b.provider.JingleS5BTransportProvider; +import org.jivesoftware.smackx.jingle.JingleManager; +import org.jivesoftware.smackx.jingle.transport.jingle_ibb.JingleIBBTransport; +import org.jivesoftware.smackx.jingle.transport.jingle_ibb.provider.JingleIBBTransportProvider; +import org.jivesoftware.smackx.jingle.transport.jingle_s5b.JingleS5BTransport; +import org.jivesoftware.smackx.jingle.transport.jingle_s5b.provider.JingleS5BTransportProvider; import org.junit.Test; @@ -34,16 +35,19 @@ public class JingleContentProviderManagerTest extends SmackTestSuite { @Test public void transportProviderTest() { - assertNull(JingleContentProviderManager.getJingleContentTransportProvider(JingleIBBTransport.NAMESPACE_V1)); - assertNull(JingleContentProviderManager.getJingleContentTransportProvider(JingleS5BTransport.NAMESPACE_V1)); + JingleManager.removeJingleTransportProvider(JingleIBBTransport.NAMESPACE_V1); + JingleManager.removeJingleTransportProvider(JingleS5BTransport.NAMESPACE_V1); + + assertNull(JingleManager.getJingleTransportProvider(JingleIBBTransport.NAMESPACE_V1)); + assertNull(JingleManager.getJingleTransportProvider(JingleS5BTransport.NAMESPACE_V1)); JingleIBBTransportProvider ibbProvider = new JingleIBBTransportProvider(); - JingleContentProviderManager.addJingleContentTransportProvider(JingleIBBTransport.NAMESPACE_V1, ibbProvider); - assertEquals(ibbProvider, JingleContentProviderManager.getJingleContentTransportProvider(JingleIBBTransport.NAMESPACE_V1)); + JingleManager.addJingleTransportProvider(ibbProvider); + assertEquals(ibbProvider, JingleManager.getJingleTransportProvider(JingleIBBTransport.NAMESPACE_V1)); - assertNull(JingleContentProviderManager.getJingleContentTransportProvider(JingleS5BTransport.NAMESPACE_V1)); + assertNull(JingleManager.getJingleTransportProvider(JingleS5BTransport.NAMESPACE_V1)); JingleS5BTransportProvider s5bProvider = new JingleS5BTransportProvider(); - JingleContentProviderManager.addJingleContentTransportProvider(JingleS5BTransport.NAMESPACE_V1, s5bProvider); - assertEquals(s5bProvider, JingleContentProviderManager.getJingleContentTransportProvider(JingleS5BTransport.NAMESPACE_V1)); + JingleManager.addJingleTransportProvider(s5bProvider); + assertEquals(s5bProvider, JingleManager.getJingleTransportProvider(JingleS5BTransport.NAMESPACE_V1)); } } diff --git a/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/provider/JingleProviderTest.java b/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/provider/JingleProviderTest.java index c3483623e..7a8f7f431 100644 --- a/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/provider/JingleProviderTest.java +++ b/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/provider/JingleProviderTest.java @@ -1,6 +1,6 @@ /** * - * Copyright 2017 Florian Schmaus + * Copyright 2017 Florian Schmaus, Paul Schaub * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,10 +21,9 @@ import static org.junit.Assert.assertEquals; import java.io.IOException; import org.jivesoftware.smack.util.PacketParserUtils; - -import org.jivesoftware.smackx.jingle.element.Jingle; -import org.jivesoftware.smackx.jingle.element.JingleContentDescription; -import org.jivesoftware.smackx.jingle.element.JingleContentTransport; +import org.jivesoftware.smackx.jingle.element.JingleContentDescriptionElement; +import org.jivesoftware.smackx.jingle.element.JingleContentTransportElement; +import org.jivesoftware.smackx.jingle.element.JingleElement; import org.junit.Test; import org.xmlpull.v1.XmlPullParser; @@ -51,9 +50,9 @@ public class JingleProviderTest { ""; // @formatter:on XmlPullParser parser = createTestJingle(unknownJingleContentDescription); - Jingle jingle = (Jingle) PacketParserUtils.parseIQ(parser); + JingleElement jingle = (JingleElement) PacketParserUtils.parseIQ(parser); - JingleContentDescription jingleContentDescription = jingle.getSoleContentOrThrow().getDescription(); + JingleContentDescriptionElement jingleContentDescription = jingle.getSoleContentOrThrow().getDescription(); String parsedUnknownJingleContentDescrptionNamespace = jingleContentDescription.getNamespace(); assertEquals(unknownJingleContentDescriptionNamespace, parsedUnknownJingleContentDescrptionNamespace); @@ -82,9 +81,9 @@ public class JingleProviderTest { ""; // @formatter:on XmlPullParser parser = createTestJingle(unknownJingleContentTransport); - Jingle jingle = (Jingle) PacketParserUtils.parseIQ(parser); + JingleElement jingle = (JingleElement) PacketParserUtils.parseIQ(parser); - JingleContentTransport jingleContentTransport = jingle.getSoleContentOrThrow().getTransport(); + JingleContentTransportElement jingleContentTransport = jingle.getSoleContentOrThrow().getTransport(); String parsedUnknownJingleContentTransportNamespace = jingleContentTransport.getNamespace(); assertEquals(unknownJingleContentTransportNamespace, parsedUnknownJingleContentTransportNamespace); diff --git a/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/transport/JingleTransportComparatorTest.java b/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/transport/JingleTransportComparatorTest.java new file mode 100644 index 000000000..d26ebba10 --- /dev/null +++ b/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/transport/JingleTransportComparatorTest.java @@ -0,0 +1,40 @@ +/** + * + * 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.transport; + +import static junit.framework.TestCase.assertEquals; + +import org.jivesoftware.smack.DummyConnection; +import org.jivesoftware.smack.test.util.SmackTestSuite; +import org.jivesoftware.smackx.jingle.transport.jingle_ibb.JingleIBBTransportManager; +import org.jivesoftware.smackx.jingle.transport.jingle_s5b.JingleS5BTransportManager; + +import org.junit.Test; + +public class JingleTransportComparatorTest extends SmackTestSuite { + + @Test + public void comparisonTest() { + DummyConnection dummyConnection = new DummyConnection(); + JingleIBBTransportManager loser = JingleIBBTransportManager.getInstanceFor(dummyConnection); + JingleS5BTransportManager winner = JingleS5BTransportManager.getInstanceFor(dummyConnection); + + assertEquals(-1, loser.compareTo(winner)); + assertEquals(1, winner.compareTo(loser)); + assertEquals(-1, loser.getPriority()); // IBB should always be last resort. + } +} diff --git a/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/transport/jingle_ibb/JingleIBBTransportTest.java b/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/transport/jingle_ibb/JingleIBBTransportTest.java new file mode 100644 index 000000000..c6bb37951 --- /dev/null +++ b/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/transport/jingle_ibb/JingleIBBTransportTest.java @@ -0,0 +1,90 @@ +/** + * + * 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.transport.jingle_ibb; + +import static junit.framework.TestCase.assertEquals; +import static junit.framework.TestCase.assertFalse; +import static junit.framework.TestCase.assertTrue; + +import org.jivesoftware.smack.DummyConnection; +import org.jivesoftware.smack.test.util.SmackTestSuite; +import org.jivesoftware.smack.test.util.TestUtils; +import org.jivesoftware.smack.util.StringUtils; +import org.jivesoftware.smackx.jingle.transport.jingle_ibb.element.JingleIBBTransportElement; +import org.jivesoftware.smackx.jingle.transport.jingle_ibb.provider.JingleIBBTransportProvider; + +import org.junit.Test; + +/** + * Test JingleIBBTransport provider and element. + */ +public class JingleIBBTransportTest extends SmackTestSuite { + + @Test + public void parserTest() throws Exception { + String sid = StringUtils.randomString(24); + short size = 8192; + + String xml = ""; + + JingleIBBTransport transport = new JingleIBBTransport(sid, size); + assertEquals(xml, transport.getElement().toXML().toString()); + assertEquals(size, (short) transport.getBlockSize()); + assertEquals(sid, transport.getStreamId()); + + JingleIBBTransportElement parsed = new JingleIBBTransportProvider() + .parse(TestUtils.getParser(xml)); + assertEquals(transport.getElement(), parsed); + assertTrue(transport.getElement().equals(parsed)); + assertEquals(xml, parsed.toXML().toString()); + + JingleIBBTransport transport1 = new JingleIBBTransport(); + assertEquals(JingleIBBTransport.DEFAULT_BLOCK_SIZE, transport1.getBlockSize()); + + assertFalse(transport.equals(null)); + + JingleIBBTransport transport2 = new JingleIBBTransport(transport1.getStreamId(), (short) 256); + assertEquals((Short) (short) 256, transport2.getBlockSize()); + assertFalse(transport1.equals(transport2)); + + transport1.handleSessionAccept(transport2.getElement(), null); + assertEquals(transport2.getBlockSize(), transport1.getBlockSize()); + + JingleIBBTransport transport3 = new JingleIBBTransportAdapter().transportFromElement(transport2.getElement()); + assertEquals(transport2.getBlockSize(), transport3.getBlockSize()); + assertEquals(transport2.getStreamId(), transport3.getStreamId()); + } + + @Test + public void jingleIBBTransportManagerTest() { + JingleIBBTransportManager manager = JingleIBBTransportManager.getInstanceFor(new DummyConnection()); + + JingleIBBTransport transport1 = (JingleIBBTransport) manager.createTransportForInitiator(null); + assertEquals(JingleIBBTransport.DEFAULT_BLOCK_SIZE, transport1.getBlockSize()); + + JingleIBBTransport transport2 = new JingleIBBTransport("sid", (short) 256); + + JingleIBBTransport transport3 = (JingleIBBTransport) manager.createTransportForResponder(null, transport2); + assertEquals((Short) (short) 256, transport3.getBlockSize()); + + JingleIBBTransport transport4 = new JingleIBBTransport("sod", Short.MAX_VALUE); + assertEquals((Short) Short.MAX_VALUE, transport4.getBlockSize()); + + JingleIBBTransport transport5 = (JingleIBBTransport) manager.createTransportForResponder(null, transport4); + assertEquals(JingleIBBTransport.MAX_BLOCKSIZE, transport5.getBlockSize()); + } +} diff --git a/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/JingleS5BTransportTest.java b/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/JingleS5BTransportTest.java new file mode 100644 index 000000000..02552367e --- /dev/null +++ b/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/JingleS5BTransportTest.java @@ -0,0 +1,311 @@ +/** + * + * 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.transport.jingle_s5b; + +import static junit.framework.TestCase.assertEquals; +import static junit.framework.TestCase.assertFalse; +import static junit.framework.TestCase.assertNotNull; +import static junit.framework.TestCase.assertNull; +import static junit.framework.TestCase.assertTrue; + +import java.util.ArrayList; +import java.util.List; + +import org.jivesoftware.smack.test.util.SmackTestSuite; +import org.jivesoftware.smack.test.util.TestUtils; +import org.jivesoftware.smackx.bytestreams.socks5.Socks5Utils; +import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream; +import org.jivesoftware.smackx.jingle.component.JingleContent; +import org.jivesoftware.smackx.jingle.component.JingleTransportCandidate; +import org.jivesoftware.smackx.jingle.element.JingleContentElement; +import org.jivesoftware.smackx.jingle.transport.jingle_s5b.element.JingleS5BTransportCandidateElement; +import org.jivesoftware.smackx.jingle.transport.jingle_s5b.element.JingleS5BTransportElement; +import org.jivesoftware.smackx.jingle.transport.jingle_s5b.element.JingleS5BTransportInfoElement; +import org.jivesoftware.smackx.jingle.transport.jingle_s5b.provider.JingleS5BTransportProvider; + +import org.junit.Test; +import org.jxmpp.jid.FullJid; +import org.jxmpp.jid.impl.JidCreate; +import org.jxmpp.stringprep.XmppStringprepException; + +/** + * Test Provider and serialization. + */ +public class JingleS5BTransportTest extends SmackTestSuite { + + @Test + public void candidatesProviderTest() throws Exception { + String xml = + "" + + + "" + + + "" + + + "" + + + ""; + JingleS5BTransportElement transportElement = new JingleS5BTransportProvider().parse(TestUtils.getParser(xml)); + assertEquals("972b7bf47291ca609517f67f86b5081086052dad", transportElement.getDestinationAddress()); + assertEquals("vj3hs98y", transportElement.getStreamId()); + assertEquals(Bytestream.Mode.tcp, transportElement.getMode()); + assertEquals(3, transportElement.getCandidates().size()); + + assertTrue(transportElement.hasCandidate("hft54dqy")); + assertFalse(transportElement.hasCandidate("invalidId")); + JingleS5BTransportCandidateElement candidate1 = + (JingleS5BTransportCandidateElement) transportElement.getCandidates().get(0); + assertEquals(candidate1, transportElement.getCandidate("hft54dqy")); + assertNotNull(candidate1.getStreamHost()); + assertEquals(JingleS5BTransportCandidateElement.Type.direct.getWeight(), candidate1.getType().getWeight()); + assertEquals("hft54dqy", candidate1.getCandidateId()); + assertEquals("192.168.4.1", candidate1.getHost()); + assertEquals(JidCreate.from("romeo@montague.lit/orchard"), candidate1.getJid()); + assertEquals(5086, candidate1.getPort()); + assertEquals(8257636, candidate1.getPriority()); + assertEquals(JingleS5BTransportCandidateElement.Type.direct, candidate1.getType()); + + JingleS5BTransportCandidateElement candidate2 = + (JingleS5BTransportCandidateElement) transportElement.getCandidates().get(1); + assertEquals("hutr46fe", candidate2.getCandidateId()); + assertEquals("24.24.24.1", candidate2.getHost()); + assertEquals(JidCreate.from("romeo@montague.lit/orchard"), candidate2.getJid()); + assertEquals(5087, candidate2.getPort()); + assertEquals(8258636, candidate2.getPriority()); + assertEquals(JingleS5BTransportCandidateElement.Type.direct, candidate2.getType()); + + JingleS5BTransportCandidateElement candidate3 = + (JingleS5BTransportCandidateElement) transportElement.getCandidates().get(2); + assertEquals("xmdh4b7i", candidate3.getCandidateId()); + assertEquals("123.456.7.8", candidate3.getHost()); + assertEquals(JidCreate.domainBareFrom("streamer.shakespeare.lit"), candidate3.getJid()); + assertEquals(7625, candidate3.getPort()); + assertEquals(7878787, candidate3.getPriority()); + assertEquals(JingleS5BTransportCandidateElement.Type.proxy, candidate3.getType()); + + assertEquals(xml, transportElement.toXML().toString()); + + JingleS5BTransport transport = new JingleS5BTransportAdapter().transportFromElement(transportElement); + assertNotNull(transport); + assertEquals(transportElement.getStreamId(), transport.getStreamId()); + assertEquals(transportElement.getMode(), transport.getMode()); + assertEquals(transportElement.getDestinationAddress(), transport.getTheirDstAddr()); + assertNull(transport.getOurDstAddr()); + assertNotNull(transport.getOurCandidates()); + assertEquals(0, transport.getOurCandidates().size()); + assertNotNull(transport.getTheirCandidates()); + assertEquals(3, transport.getTheirCandidates().size()); + + for (int i = 0; i < transport.getTheirCandidates().size() - 1; i++) { + assertTrue(transport.getTheirCandidates().get(i).getPriority() >= transport.getTheirCandidates().get(i + 1).getPriority()); + } + + JingleTransportCandidate c = transport.getTheirCandidates().get(1); + transport.addTheirCandidate(c); + + assertEquals(3, transport.getTheirCandidates().size()); + assertTrue(c.getParent() == transport); + + assertNull(transport.getParent()); + + JingleContent content = new JingleContent(JingleContentElement.Creator.initiator, JingleContentElement.Senders.initiator); + assertNull(content.getTransport()); + + content.setTransport(transport); + assertEquals(transport, content.getTransport()); + assertEquals(content, transport.getParent()); + } + + @Test + public void infoProviderTest() throws Exception { + String candidateError = + "" + + "" + + ""; + JingleS5BTransportElement candidateErrorTransport = new JingleS5BTransportProvider() + .parse(TestUtils.getParser(candidateError)); + assertNull(candidateErrorTransport.getDestinationAddress()); + assertNotNull(candidateErrorTransport.getInfo()); + assertEquals("vj3hs98y", candidateErrorTransport.getStreamId()); + assertEquals(JingleS5BTransportInfoElement.CandidateError.INSTANCE, + candidateErrorTransport.getInfo()); + assertEquals(candidateError, candidateErrorTransport.toXML().toString()); + + String proxyError = + "" + + "" + + ""; + JingleS5BTransportElement proxyErrorTransport = new JingleS5BTransportProvider() + .parse(TestUtils.getParser(proxyError)); + assertNull(proxyErrorTransport.getDestinationAddress()); + assertNotNull(proxyErrorTransport.getInfo()); + assertNotNull(candidateErrorTransport.getInfo()); + assertEquals("vj3hs98y", proxyErrorTransport.getStreamId()); + assertEquals(JingleS5BTransportInfoElement.ProxyError.INSTANCE, + proxyErrorTransport.getInfo()); + assertEquals(proxyError, proxyErrorTransport.toXML().toString()); + + String candidateUsed = + "" + + "" + + ""; + JingleS5BTransportElement candidateUsedTransport = new JingleS5BTransportProvider() + .parse(TestUtils.getParser(candidateUsed)); + assertNotNull(candidateUsedTransport.getInfo()); + assertEquals(new JingleS5BTransportInfoElement.CandidateUsed("hr65dqyd"), + candidateUsedTransport.getInfo()); + assertEquals("hr65dqyd", + ((JingleS5BTransportInfoElement.CandidateUsed) + candidateUsedTransport.getInfo()).getCandidateId()); + assertEquals(candidateUsed, candidateUsedTransport.toXML().toString()); + + String candidateActivated = + "" + + "" + + ""; + JingleS5BTransportElement candidateActivatedTransport = new JingleS5BTransportProvider() + .parse(TestUtils.getParser(candidateActivated)); + assertNotNull(candidateActivatedTransport.getInfo()); + assertNotNull(candidateErrorTransport.getInfo()); + + assertEquals(new JingleS5BTransportInfoElement.CandidateActivated("hr65dqyd"), + candidateActivatedTransport.getInfo()); + assertEquals("hr65dqyd", + ((JingleS5BTransportInfoElement.CandidateActivated) + candidateActivatedTransport.getInfo()).getCandidateId()); + assertEquals(candidateActivated, candidateActivatedTransport.toXML().toString()); + } + + @Test(expected = IllegalArgumentException.class) + public void candidateBuilderInvalidPortTest() { + JingleS5BTransportCandidateElement.getBuilder().setPort(-5); + } + + @Test(expected = IllegalArgumentException.class) + public void candidateBuilderInvalidPriorityTest() { + JingleS5BTransportCandidateElement.getBuilder().setPriority(-1000); + } + + @Test(expected = IllegalArgumentException.class) + public void transportCandidateIllegalPriorityTest() throws XmppStringprepException { + FullJid jid = JidCreate.fullFrom("test@test.test/test"); + JingleS5BTransportCandidateElement candidate = new JingleS5BTransportCandidateElement( + "cid", "host", jid, 5555, -30, JingleS5BTransportCandidateElement.Type.proxy); + } + + @Test(expected = IllegalArgumentException.class) + public void transportCandidateIllegalPortTest() throws XmppStringprepException { + FullJid jid = JidCreate.fullFrom("test@test.test/test"); + JingleS5BTransportCandidateElement candidate = new JingleS5BTransportCandidateElement( + "cid", "host", jid, -5555, 30, JingleS5BTransportCandidateElement.Type.proxy); + } + + @Test + public void candidateFromStreamHostTest() throws XmppStringprepException { + FullJid jid = JidCreate.fullFrom("test@test.test/test"); + String host = "host.address"; + int port = 1234; + Bytestream.StreamHost streamHost = new Bytestream.StreamHost(jid, host, port); + + JingleS5BTransportCandidateElement candidate = new JingleS5BTransportCandidateElement(streamHost, 2000, JingleS5BTransportCandidateElement.Type.direct); + + assertEquals(2000, candidate.getPriority()); + assertEquals(jid, candidate.getJid()); + assertEquals(host, candidate.getHost()); + assertEquals(port, candidate.getPort()); + + assertEquals(streamHost.toXML().toString(), candidate.getStreamHost().toXML().toString()); + } + + @Test + public void constructorsTest() throws XmppStringprepException { + FullJid initiator = JidCreate.fullFrom("in@it.ia/tor"); + FullJid responder = JidCreate.fullFrom("re@sp.on/der"); + + List> c1 = new ArrayList<>(); + JingleS5BTransportCandidate c11 = new JingleS5BTransportCandidate("1234", new Bytestream.StreamHost(JidCreate.from("p.b.c"), "p.b.c", 9999), 100, JingleS5BTransportCandidateElement.Type.proxy); + c1.add(c11); + + List> c2 = new ArrayList<>(); + JingleS5BTransportCandidate c21 = new JingleS5BTransportCandidate("1337", new Bytestream.StreamHost(JidCreate.from("p.a.b"), "p.a.b", 1000), 101, JingleS5BTransportCandidateElement.Type.proxy); + JingleS5BTransportCandidate c22 = new JingleS5BTransportCandidate("1009", new Bytestream.StreamHost(JidCreate.from("p.a.b"), "p.a.b", 2000), 10, JingleS5BTransportCandidateElement.Type.proxy); + c2.add(c21); + c2.add(c22); + + + JingleS5BTransport t1 = new JingleS5BTransport(initiator, responder, "tSes", Bytestream.Mode.tcp, c1); + + assertEquals("tSes", t1.getStreamId()); + assertEquals(Bytestream.Mode.tcp, t1.getMode()); + + assertEquals(Socks5Utils.createDigest("tSes", initiator, responder), t1.getOurDstAddr()); + assertNull(t1.getTheirDstAddr()); + + assertEquals(1, t1.getOurCandidates().size()); + assertEquals(c11, t1.getOurCandidates().get(0)); + assertEquals(0, t1.getTheirCandidates().size()); + + + JingleS5BTransport t1parsed = new JingleS5BTransportAdapter().transportFromElement(t1.getElement()); + + assertEquals(t1.getOurDstAddr(), t1parsed.getTheirDstAddr()); + assertNull(t1parsed.getOurDstAddr()); + assertEquals(0, t1parsed.getOurCandidates().size()); + assertEquals(t1.getStreamId(), t1parsed.getStreamId()); + assertEquals(t1.getMode(), t1parsed.getMode()); + assertEquals(t1.getOurCandidates().size(), t1parsed.getTheirCandidates().size()); + + JingleS5BTransport t2 = new JingleS5BTransport(initiator, responder, c2, t1parsed); + + assertEquals("tSes", t2.getStreamId()); + assertEquals(Bytestream.Mode.tcp, t2.getMode()); + + assertEquals(Socks5Utils.createDigest("tSes", responder, initiator), t2.getOurDstAddr()); + assertEquals(t1.getOurDstAddr(), t2.getTheirDstAddr()); + + assertEquals(2, t2.getOurCandidates().size()); + assertEquals(c2, t2.getOurCandidates()); + assertEquals(t1.getOurCandidates().size(), t2.getTheirCandidates().size()); + } + + @Test(expected = IllegalArgumentException.class) + public void typeFromIllegalStringTest() { + JingleS5BTransportCandidateElement.Type.fromString("illegal-type"); + } +} diff --git a/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/transports/jingle_ibb/JingleIBBTransportTest.java b/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/transports/jingle_ibb/JingleIBBTransportTest.java deleted file mode 100644 index e33b2b814..000000000 --- a/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/transports/jingle_ibb/JingleIBBTransportTest.java +++ /dev/null @@ -1,76 +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.jingle_ibb; - -import static junit.framework.TestCase.assertEquals; -import static junit.framework.TestCase.assertFalse; -import static junit.framework.TestCase.assertNotSame; -import static junit.framework.TestCase.assertTrue; - -import org.jivesoftware.smack.test.util.SmackTestSuite; -import org.jivesoftware.smack.test.util.TestUtils; -import org.jivesoftware.smack.util.StringUtils; - -import org.jivesoftware.smackx.jingle.transports.jingle_ibb.element.JingleIBBTransport; -import org.jivesoftware.smackx.jingle.transports.jingle_ibb.provider.JingleIBBTransportProvider; - -import org.junit.Test; - -/** - * Test JingleIBBTransport provider and element. - */ -public class JingleIBBTransportTest extends SmackTestSuite { - - @Test - public void parserTest() throws Exception { - String sid = StringUtils.randomString(24); - short size = 8192; - - String xml = ""; - - JingleIBBTransport transport = new JingleIBBTransport(size, sid); - assertEquals(xml, transport.toXML().toString()); - assertEquals(size, transport.getBlockSize()); - assertEquals(sid, transport.getSessionId()); - - JingleIBBTransport parsed = new JingleIBBTransportProvider() - .parse(TestUtils.getParser(xml)); - assertEquals(transport, parsed); - assertTrue(transport.equals(parsed)); - assertEquals(xml, parsed.toXML().toString()); - - JingleIBBTransport transport1 = new JingleIBBTransport((short) 1024); - assertEquals((short) 1024, transport1.getBlockSize()); - assertNotSame(transport, transport1); - assertNotSame(transport.getSessionId(), transport1.getSessionId()); - - assertFalse(transport.equals(null)); - - JingleIBBTransport transport2 = new JingleIBBTransport(); - assertEquals(JingleIBBTransport.DEFAULT_BLOCK_SIZE, transport2.getBlockSize()); - assertFalse(transport1.equals(transport2)); - - JingleIBBTransport transport3 = new JingleIBBTransport((short) -1024); - assertEquals(JingleIBBTransport.DEFAULT_BLOCK_SIZE, transport3.getBlockSize()); - - assertEquals(transport3.getNamespace(), JingleIBBTransport.NAMESPACE_V1); - assertEquals(transport3.getElementName(), "transport"); - - JingleIBBTransport transport4 = new JingleIBBTransport("session-id"); - assertEquals(JingleIBBTransport.DEFAULT_BLOCK_SIZE, transport4.getBlockSize()); - } -} diff --git a/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/transports/jingle_s5b/JingleS5BTransportTest.java b/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/transports/jingle_s5b/JingleS5BTransportTest.java deleted file mode 100644 index 68ca37f06..000000000 --- a/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/transports/jingle_s5b/JingleS5BTransportTest.java +++ /dev/null @@ -1,226 +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.jingle_s5b; - -import static junit.framework.TestCase.assertEquals; -import static junit.framework.TestCase.assertFalse; -import static junit.framework.TestCase.assertNotNull; -import static junit.framework.TestCase.assertNull; -import static junit.framework.TestCase.assertTrue; - -import org.jivesoftware.smack.test.util.SmackTestSuite; - -import org.jivesoftware.smack.test.util.TestUtils; -import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream; -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.elements.JingleS5BTransportInfo; -import org.jivesoftware.smackx.jingle.transports.jingle_s5b.provider.JingleS5BTransportProvider; - -import org.junit.Test; -import org.jxmpp.jid.FullJid; -import org.jxmpp.jid.impl.JidCreate; -import org.jxmpp.stringprep.XmppStringprepException; - -/** - * Test Provider and serialization. - */ -public class JingleS5BTransportTest extends SmackTestSuite { - - @Test - public void candidatesProviderTest() throws Exception { - String xml = - "" + - - "" + - - "" + - - "" + - - ""; - JingleS5BTransport transport = new JingleS5BTransportProvider().parse(TestUtils.getParser(xml)); - assertEquals("972b7bf47291ca609517f67f86b5081086052dad", transport.getDestinationAddress()); - assertEquals("vj3hs98y", transport.getStreamId()); - assertEquals(Bytestream.Mode.tcp, transport.getMode()); - assertEquals(3, transport.getCandidates().size()); - - assertTrue(transport.hasCandidate("hft54dqy")); - assertFalse(transport.hasCandidate("invalidId")); - JingleS5BTransportCandidate candidate1 = - (JingleS5BTransportCandidate) transport.getCandidates().get(0); - assertEquals(candidate1, transport.getCandidate("hft54dqy")); - assertNotNull(candidate1.getStreamHost()); - assertEquals(JingleS5BTransportCandidate.Type.direct.getWeight(), candidate1.getType().getWeight()); - assertEquals("hft54dqy", candidate1.getCandidateId()); - assertEquals("192.168.4.1", candidate1.getHost()); - assertEquals(JidCreate.from("romeo@montague.lit/orchard"), candidate1.getJid()); - assertEquals(5086, candidate1.getPort()); - assertEquals(8257636, candidate1.getPriority()); - assertEquals(JingleS5BTransportCandidate.Type.direct, candidate1.getType()); - - JingleS5BTransportCandidate candidate2 = - (JingleS5BTransportCandidate) transport.getCandidates().get(1); - assertEquals("hutr46fe", candidate2.getCandidateId()); - assertEquals("24.24.24.1", candidate2.getHost()); - assertEquals(JidCreate.from("romeo@montague.lit/orchard"), candidate2.getJid()); - assertEquals(5087, candidate2.getPort()); - assertEquals(8258636, candidate2.getPriority()); - assertEquals(JingleS5BTransportCandidate.Type.direct, candidate2.getType()); - - JingleS5BTransportCandidate candidate3 = - (JingleS5BTransportCandidate) transport.getCandidates().get(2); - assertEquals("xmdh4b7i", candidate3.getCandidateId()); - assertEquals("123.456.7.8", candidate3.getHost()); - assertEquals(JidCreate.domainBareFrom("streamer.shakespeare.lit"), candidate3.getJid()); - assertEquals(7625, candidate3.getPort()); - assertEquals(7878787, candidate3.getPriority()); - assertEquals(JingleS5BTransportCandidate.Type.proxy, candidate3.getType()); - - assertEquals(xml, transport.toXML().toString()); - } - - @Test - public void infoProviderTest() throws Exception { - String candidateError = - "" + - "" + - ""; - JingleS5BTransport candidateErrorTransport = new JingleS5BTransportProvider() - .parse(TestUtils.getParser(candidateError)); - assertNull(candidateErrorTransport.getDestinationAddress()); - assertNotNull(candidateErrorTransport.getInfo()); - assertEquals("vj3hs98y", candidateErrorTransport.getStreamId()); - assertEquals(JingleS5BTransportInfo.CandidateError.INSTANCE, - candidateErrorTransport.getInfo()); - assertEquals(candidateError, candidateErrorTransport.toXML().toString()); - - String proxyError = - "" + - "" + - ""; - JingleS5BTransport proxyErrorTransport = new JingleS5BTransportProvider() - .parse(TestUtils.getParser(proxyError)); - assertNull(proxyErrorTransport.getDestinationAddress()); - assertNotNull(proxyErrorTransport.getInfo()); - assertNotNull(candidateErrorTransport.getInfo()); - assertEquals("vj3hs98y", proxyErrorTransport.getStreamId()); - assertEquals(JingleS5BTransportInfo.ProxyError.INSTANCE, - proxyErrorTransport.getInfo()); - assertEquals(proxyError, proxyErrorTransport.toXML().toString()); - - String candidateUsed = - "" + - "" + - ""; - JingleS5BTransport candidateUsedTransport = new JingleS5BTransportProvider() - .parse(TestUtils.getParser(candidateUsed)); - assertNotNull(candidateUsedTransport.getInfo()); - assertEquals(new JingleS5BTransportInfo.CandidateUsed("hr65dqyd"), - candidateUsedTransport.getInfo()); - assertEquals("hr65dqyd", - ((JingleS5BTransportInfo.CandidateUsed) - candidateUsedTransport.getInfo()).getCandidateId()); - assertEquals(candidateUsed, candidateUsedTransport.toXML().toString()); - - String candidateActivated = - "" + - "" + - ""; - JingleS5BTransport candidateActivatedTransport = new JingleS5BTransportProvider() - .parse(TestUtils.getParser(candidateActivated)); - assertNotNull(candidateActivatedTransport.getInfo()); - assertNotNull(candidateErrorTransport.getInfo()); - - assertEquals(new JingleS5BTransportInfo.CandidateActivated("hr65dqyd"), - candidateActivatedTransport.getInfo()); - assertEquals("hr65dqyd", - ((JingleS5BTransportInfo.CandidateActivated) - candidateActivatedTransport.getInfo()).getCandidateId()); - assertEquals(candidateActivated, candidateActivatedTransport.toXML().toString()); - } - - @Test(expected = IllegalArgumentException.class) - public void candidateBuilderInvalidPortTest() { - JingleS5BTransportCandidate.getBuilder().setPort(-5); - } - - @Test(expected = IllegalArgumentException.class) - public void candidateBuilderInvalidPriorityTest() { - JingleS5BTransportCandidate.getBuilder().setPriority(-1000); - } - - @Test(expected = IllegalArgumentException.class) - public void transportCandidateIllegalPriorityTest() throws XmppStringprepException { - FullJid jid = JidCreate.fullFrom("test@test.test/test"); - @SuppressWarnings("unused") - JingleS5BTransportCandidate candidate = new JingleS5BTransportCandidate( - "cid", "host", jid, 5555, -30, JingleS5BTransportCandidate.Type.proxy); - } - - @Test(expected = IllegalArgumentException.class) - public void transportCandidateIllegalPortTest() throws XmppStringprepException { - FullJid jid = JidCreate.fullFrom("test@test.test/test"); - @SuppressWarnings("unused") - JingleS5BTransportCandidate candidate = new JingleS5BTransportCandidate( - "cid", "host", jid, -5555, 30, JingleS5BTransportCandidate.Type.proxy); - } - - @Test - public void candidateFromStreamHostTest() throws XmppStringprepException { - FullJid jid = JidCreate.fullFrom("test@test.test/test"); - String host = "host.address"; - int port = 1234; - Bytestream.StreamHost streamHost = new Bytestream.StreamHost(jid, host, port); - - JingleS5BTransportCandidate candidate = new JingleS5BTransportCandidate(streamHost, 2000, JingleS5BTransportCandidate.Type.direct); - - assertEquals(2000, candidate.getPriority()); - assertEquals(jid, candidate.getJid()); - assertEquals(host, candidate.getHost()); - assertEquals(port, candidate.getPort()); - - assertEquals(streamHost.toXML().toString(), candidate.getStreamHost().toXML().toString()); - } - - @Test(expected = IllegalArgumentException.class) - public void typeFromIllegalStringTest() { - JingleS5BTransportCandidate.Type.fromString("illegal-type"); - } -} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/package-info.java b/smack-integration-test/src/main/java/org/jivesoftware/smackx/jingle/package-info.java similarity index 79% rename from smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/package-info.java rename to smack-integration-test/src/main/java/org/jivesoftware/smackx/jingle/package-info.java index 86fb45ecc..a990a47b9 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/package-info.java +++ b/smack-integration-test/src/main/java/org/jivesoftware/smackx/jingle/package-info.java @@ -16,6 +16,6 @@ */ /** - * Smack's API for XEP-0234: Jingle File Transfer. + * Tests for Jingle. */ -package org.jivesoftware.smackx.jingle_filetransfer; +package org.jivesoftware.smackx.jingle; 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 new file mode 100644 index 000000000..c34ab0227 --- /dev/null +++ b/smack-integration-test/src/main/java/org/jivesoftware/smackx/jingle/transport/JingleTransportIntegrationTest.java @@ -0,0 +1,191 @@ +/** + * + * 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.transport; + +import static junit.framework.TestCase.fail; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Random; +import java.util.logging.Level; + +import org.jivesoftware.smack.XMPPConnection; +import org.jivesoftware.smack.util.Async; +import org.jivesoftware.smackx.bytestreams.BytestreamSession; +import org.jivesoftware.smackx.bytestreams.socks5.Socks5Proxy; +import org.jivesoftware.smackx.jingle.JingleManager; +import org.jivesoftware.smackx.jingle.callbacks.JingleTransportCallback; +import org.jivesoftware.smackx.jingle.component.JingleContent; +import org.jivesoftware.smackx.jingle.component.JingleSession; +import org.jivesoftware.smackx.jingle.component.JingleTransport; +import org.jivesoftware.smackx.jingle.element.JingleContentElement; +import org.jivesoftware.smackx.jingle.transport.jingle_ibb.JingleIBBTransport; +import org.jivesoftware.smackx.jingle.transport.jingle_s5b.JingleS5BTransport; +import org.jivesoftware.smackx.jingle.transport.jingle_s5b.JingleS5BTransportManager; +import org.jivesoftware.smackx.jingle.util.Role; + +import org.igniterealtime.smack.inttest.AbstractSmackIntegrationTest; +import org.igniterealtime.smack.inttest.SmackIntegrationTest; +import org.igniterealtime.smack.inttest.SmackIntegrationTestEnvironment; +import org.igniterealtime.smack.inttest.util.SimpleResultSyncPoint; +import org.junit.After; +import org.junit.Assert; + +/** + * Test the JingleIBBTransport in a very basic case. + */ +public class JingleTransportIntegrationTest extends AbstractSmackIntegrationTest { + + public JingleTransportIntegrationTest(SmackIntegrationTestEnvironment environment) { + super(environment); + } + + @SmackIntegrationTest + public void JingleIBBTest() throws Exception { + XMPPConnection sender = conOne; + XMPPConnection receiver = conTwo; + + JingleIBBTransport sTransport = new JingleIBBTransport(); + JingleIBBTransport rTransport = new JingleIBBTransport(sTransport.getStreamId(), sTransport.getBlockSize()); + + JingleSession sSession = new JingleSession(JingleManager.getInstanceFor(sender), sender.getUser().asFullJidOrThrow(), receiver.getUser().asFullJidOrThrow(), Role.initiator, "session"); + JingleSession rSession = new JingleSession(JingleManager.getInstanceFor(receiver), sender.getUser().asFullJidOrThrow(), receiver.getUser().asFullJidOrThrow(), Role.responder, "session"); + + basicTransportTest(sSession, rSession, sTransport, rTransport); + } + + @SmackIntegrationTest + public void JingleS5BTest() throws Exception { + Socks5Proxy socks5Proxy = Socks5Proxy.getSocks5Proxy(); + if (!socks5Proxy.isRunning()) { + socks5Proxy.start(); + } + + XMPPConnection sender = conOne; + XMPPConnection receiver = conTwo; + JingleSession sSession = new JingleSession(JingleManager.getInstanceFor(sender), sender.getUser().asFullJidOrThrow(), receiver.getUser().asFullJidOrThrow(), Role.initiator, "session"); + JingleSession rSession = new JingleSession(JingleManager.getInstanceFor(receiver), sender.getUser().asFullJidOrThrow(), receiver.getUser().asFullJidOrThrow(), Role.responder, "session"); + LOGGER.log(Level.INFO, sender.getUser().asFullJidOrThrow() + " adds " + sSession.getPeer() + " " + sSession.getSessionId()); + JingleManager.getInstanceFor(sender).addSession(sSession); + LOGGER.log(Level.INFO, receiver.getUser().asFullJidOrThrow() + " adds " + rSession.getPeer() + " " + rSession.getSessionId()); + JingleManager.getInstanceFor(receiver).addSession(rSession); + + JingleContent sContent = new JingleContent(null, null, null, "content", null, JingleContentElement.Creator.initiator, JingleContentElement.Senders.initiator); + JingleContent rContent = new JingleContent(null, null, null, "content", null, JingleContentElement.Creator.initiator, JingleContentElement.Senders.initiator); + sSession.addContent(sContent); + rSession.addContent(rContent); + JingleS5BTransport sTransport = (JingleS5BTransport) JingleS5BTransportManager.getInstanceFor(sender).createTransportForInitiator(sContent); + JingleS5BTransport rTransport = (JingleS5BTransport) JingleS5BTransportManager.getInstanceFor(receiver).createTransportForResponder(rContent, sTransport); + sContent.setTransport(sTransport); + rContent.setTransport(rTransport); + sTransport.handleSessionAccept(rTransport.getElement(), sender); + rTransport.handleSessionAccept(sTransport.getElement(), receiver); + + basicTransportTest(sSession, rSession, sTransport, rTransport); + } + + + public void basicTransportTest(JingleSession sSession, JingleSession rSession, final JingleTransport sTransport, final JingleTransport rTransport) throws Exception { + final SimpleResultSyncPoint recvPoint = new SimpleResultSyncPoint(); + + final int size = 16000; + final byte[] data = new byte[size]; + new Random().nextBytes(data); + final byte[] recv = new byte[size]; + + rTransport.establishIncomingBytestreamSession(rSession.getJingleManager().getConnection(), new JingleTransportCallback() { + @Override + public void onTransportReady(final BytestreamSession bytestreamSession) { + LOGGER.log(Level.INFO, "Receiving!"); + Async.go(new Runnable() { + @Override + public void run() { + try { + InputStream inputStream = bytestreamSession.getInputStream(); + + byte[] buf = new byte[512]; + int read = 0; + while (read < size) { + int r = inputStream.read(buf); + if (r >= 0) { + System.arraycopy(buf, 0, recv, read, r); + read += r; + } else { + break; + } + LOGGER.log(Level.INFO, "Read " + r + " bytes (" + read + " of " + size + ")"); + } + + LOGGER.log(Level.INFO, "Success!"); + + bytestreamSession.getInputStream().close(); + recvPoint.signal(); + } catch (IOException e) { + fail(e.toString()); + } + } + }); + } + + @Override + public void onTransportFailed(Exception e) { + LOGGER.log(Level.SEVERE, e.toString()); + recvPoint.signal(); + } + }, rSession); + + sTransport.establishOutgoingBytestreamSession(sSession.getJingleManager().getConnection(), new JingleTransportCallback() { + @Override + public void onTransportReady(final BytestreamSession bytestreamSession) { + LOGGER.log(Level.INFO, "Sending!"); + Async.go(new Runnable() { + @Override + public void run() { + try { + OutputStream outputStream = bytestreamSession.getOutputStream(); + outputStream.write(data); + outputStream.flush(); + + } catch (IOException e) { + fail(e.toString()); + } + LOGGER.log(Level.INFO, "Sending finished!"); + } + }); + } + + @Override + public void onTransportFailed(Exception e) { + LOGGER.log(Level.SEVERE, e.toString()); + } + }, sSession); + + recvPoint.waitForResult(60 * 1000); + Assert.assertArrayEquals(data, recv); + sSession.getJingleManager().removeSession(sSession); + rSession.getJingleManager().removeSession(rSession); + } + + @After + public void tearDown() { + Socks5Proxy socks5Proxy = Socks5Proxy.getSocks5Proxy(); + if (socks5Proxy.isRunning()) { + socks5Proxy.stop(); + } + } +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_ibb/package-info.java b/smack-integration-test/src/main/java/org/jivesoftware/smackx/jingle/transport/package-info.java similarity index 77% rename from smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_ibb/package-info.java rename to smack-integration-test/src/main/java/org/jivesoftware/smackx/jingle/transport/package-info.java index b42da7b09..9e855d8d4 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_ibb/package-info.java +++ b/smack-integration-test/src/main/java/org/jivesoftware/smackx/jingle/transport/package-info.java @@ -16,6 +16,6 @@ */ /** - * Smack's API for XEP-0261: Jingle In-Band Bytestreams. + * Tests for Tests for different Jingle transport methods. */ -package org.jivesoftware.smackx.jingle.transports.jingle_ibb; +package org.jivesoftware.smackx.jingle.transport;