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/JingleContentTransport.java index 156caf3cd..49f6dc66a 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/JingleContentTransport.java @@ -74,7 +74,7 @@ public abstract class JingleContentTransport implements ExtensionElement { XmlStringBuilder xml = new XmlStringBuilder(this); addExtraAttributes(xml); - if (candidates.isEmpty()) { + if (candidates.isEmpty() && infos.isEmpty()) { xml.closeEmptyElement(); } else { @@ -87,5 +87,4 @@ public abstract class JingleContentTransport implements ExtensionElement { return xml; } - } 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/transports/jingle_s5b/elements/JingleS5BTransport.java new file mode 100644 index 000000000..f39248eea --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_s5b/elements/JingleS5BTransport.java @@ -0,0 +1,144 @@ +/** + * + * 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.elements; + +import java.util.ArrayList; +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; + +/** + * Socks5Bytestream transport element. + */ +public class JingleS5BTransport extends JingleContentTransport { + public static final String NAMESPACE_V1 = "urn:xmpp:jingle:transports:s5b:1"; + 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 dstAddr; + private final Bytestream.Mode mode; + + protected JingleS5BTransport(List candidates, List infos, String streamId, String dstAddr, Bytestream.Mode mode) { + super(candidates, infos); + StringUtils.requireNotNullOrEmpty(streamId, "sid MUST be neither null, nor empty."); + this.streamId = streamId; + this.dstAddr = dstAddr; + this.mode = mode; + } + + public String getStreamId() { + return streamId; + } + + public String getDestinationAddress() { + return dstAddr; + } + + public Bytestream.Mode getMode() { + return mode == null ? Bytestream.Mode.tcp : mode; + } + + @Override + public String getNamespace() { + return NAMESPACE_V1; + } + + @Override + protected void addExtraAttributes(XmlStringBuilder xml) { + xml.optAttribute(ATTR_DSTADDR, dstAddr); + xml.optAttribute(ATTR_MODE, mode); + xml.attribute(ATTR_SID, streamId); + } + + public boolean hasCandidate(String candidateId) { + return getCandidate(candidateId) != null; + } + + public JingleS5BTransportCandidate getCandidate(String candidateId) { + for (JingleContentTransportCandidate c : candidates) { + JingleS5BTransportCandidate candidate = (JingleS5BTransportCandidate) c; + if (candidate.getCandidateId().equals(candidateId)) { + return candidate; + } + } + return null; + } + + public static Builder getBuilder() { + return new Builder(); + } + + public static class Builder { + private String streamId; + private String dstAddr; + private Bytestream.Mode mode; + private ArrayList candidates = new ArrayList<>(); + private ArrayList infos = new ArrayList<>(); + + public Builder setStreamId(String sid) { + this.streamId = sid; + return this; + } + + public Builder setDestinationAddress(String dstAddr) { + this.dstAddr = dstAddr; + return this; + } + + public Builder setMode(Bytestream.Mode mode) { + this.mode = mode; + return this; + } + + public Builder addTransportCandidate(JingleS5BTransportCandidate candidate) { + this.candidates.add(candidate); + return this; + } + + public Builder addTransportInfo(JingleContentTransportInfo info) { + this.infos.add(info); + return this; + } + + public Builder setCandidateUsed(String candidateId) { + return addTransportInfo(JingleS5BTransportInfo.CandidateUsed(candidateId)); + } + + public Builder setCandidateActivated(String candidateId) { + return addTransportInfo(JingleS5BTransportInfo.CandidateActivated(candidateId)); + } + + public Builder setCandidateError() { + return addTransportInfo(JingleS5BTransportInfo.CandidateError()); + } + + public Builder setProxyError() { + return addTransportInfo(JingleS5BTransportInfo.ProxyError()); + } + + public JingleS5BTransport build() { + return new JingleS5BTransport(candidates, infos, streamId, dstAddr, mode); + } + } +} 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/transports/jingle_s5b/elements/JingleS5BTransportCandidate.java new file mode 100644 index 000000000..284fc72e9 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_s5b/elements/JingleS5BTransportCandidate.java @@ -0,0 +1,200 @@ +/** + * + * 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.elements; + +import java.util.logging.Logger; + +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.jxmpp.jid.Jid; +import org.jxmpp.jid.impl.JidCreate; +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 static final String ATTR_CID = "cid"; + public static final String ATTR_HOST = "host"; + public static final String ATTR_JID = "jid"; + public static final String ATTR_PORT = "port"; + public static final String ATTR_PRIORITY = "priority"; + public static final String ATTR_TYPE = "type"; + + private final String cid; + private final String host; + private final Jid jid; + private final int port; + private final int priority; + private final Type type; + + public JingleS5BTransportCandidate(String candidateId, String host, Jid jid, int port, int priority, Type type) { + + Objects.requireNonNull(candidateId); + Objects.requireNonNull(host); + Objects.requireNonNull(jid); + if (priority < 0) { + throw new IllegalArgumentException("Priority MUST be present and NOT less than 0."); + } + + this.cid = candidateId; + this.host = host; + this.jid = jid; + this.port = port; + this.priority = priority; + this.type = type; + } + + public JingleS5BTransportCandidate(Bytestream.StreamHost streamHost, int priority) { + this(StringUtils.randomString(24), streamHost.getAddress(), streamHost.getJID(), streamHost.getPort(), priority, Type.proxy); + } + + public enum Type { + assisted (120), + direct (126), + proxy (10), + tunnel (110), + ; + + private final int weight; + + public int getWeight() { + return weight; + } + + Type(int weight) { + this.weight = weight; + } + + public static Type fromString(String name) { + for (Type t : Type.values()) { + if (t.toString().equals(name)) { + return t; + } + } + throw new IllegalArgumentException("Illegal type: " + name); + } + } + + public String getCandidateId() { + return cid; + } + + public String getHost() { + return host; + } + + public Jid getJid() { + return jid; + } + + public int getPort() { + return port; + } + + public int getPriority() { + return priority; + } + + public Type getType() { + return type; + } + + public Bytestream.StreamHost getStreamHost() { + return new Bytestream.StreamHost(jid, host, port); + } + + @Override + public CharSequence toXML() { + XmlStringBuilder xml = new XmlStringBuilder(); + xml.halfOpenElement(this); + xml.attribute(ATTR_CID, cid); + xml.attribute(ATTR_HOST, host); + xml.attribute(ATTR_JID, jid); + if (port >= 0) { + xml.attribute(ATTR_PORT, port); + } + xml.attribute(ATTR_PRIORITY, priority); + xml.optAttribute(ATTR_TYPE, type); + + xml.closeEmptyElement(); + return xml; + } + + public static Builder getBuilder() { + return new Builder(); + } + + public static final class Builder { + private String cid; + private String host; + private Jid jid; + private int port = -1; + private int priority = -1; + private Type type; + + private Builder() { + } + + public Builder setCandidateId(String cid) { + this.cid = cid; + return this; + } + + public Builder setHost(String host) { + this.host = host; + return this; + } + + public Builder setJid(String jid) throws XmppStringprepException { + this.jid = JidCreate.from(jid); + return this; + } + + public Builder setPort(int port) { + if (port < 0) { + throw new IllegalArgumentException("Port MUST NOT be less than 0."); + } + this.port = port; + return this; + } + + public Builder setPriority(int priority) { + if (priority < 0) { + throw new IllegalArgumentException("Priority MUST NOT be less than 0."); + } + this.priority = priority; + return this; + } + + public Builder setType(Type type) { + this.type = type; + return this; + } + + public JingleS5BTransportCandidate build() { + return new JingleS5BTransportCandidate(cid, host, jid, port, priority, type); + } + } +} 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/transports/jingle_s5b/elements/JingleS5BTransportInfo.java new file mode 100644 index 000000000..1cfc7ee42 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_s5b/elements/JingleS5BTransportInfo.java @@ -0,0 +1,193 @@ +/** + * + * 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.elements; + +import org.jivesoftware.smack.util.XmlStringBuilder; +import org.jivesoftware.smackx.jingle.element.JingleContentTransportInfo; + +/** + * Class representing possible SOCKS5 TransportInfo elements. + */ +public abstract class JingleS5BTransportInfo extends JingleContentTransportInfo { + + private static CandidateError CEI; + private static ProxyError PEI; + + public static CandidateUsed CandidateUsed(String candidateId) { + return new CandidateUsed(candidateId); + } + + public static CandidateActivated CandidateActivated(String candidateId) { + return new CandidateActivated(candidateId); + } + + public static CandidateError CandidateError() { + if (CEI == null) { + CEI = new CandidateError(); + } + return CEI; + } + + public static ProxyError ProxyError() { + if (PEI == null) { + PEI = new ProxyError(); + } + return PEI; + } + + public static final class CandidateActivated extends JingleS5BTransportInfo { + public static final String ELEMENT = "candidate-activated"; + public static final String ATTR_CID = "cid"; + + private final String candidateId; + + public CandidateActivated(String candidateId) { + this.candidateId = candidateId; + } + + public String getCandidateId() { + return candidateId; + } + + @Override + public String getElementName() { + return ELEMENT; + } + + @Override + public CharSequence toXML() { + XmlStringBuilder xml = new XmlStringBuilder(); + xml.halfOpenElement(this); + xml.attribute(ATTR_CID, candidateId); + xml.closeEmptyElement(); + return xml; + } + + @Override + public boolean equals(Object other) { + return other instanceof CandidateActivated && + ((CandidateActivated) other).getCandidateId().equals(candidateId); + } + + @Override + public int hashCode() { + return toXML().toString().hashCode(); + } + } + + public static final class CandidateUsed extends JingleS5BTransportInfo { + public static final String ELEMENT = "candidate-used"; + public static final String ATTR_CID = "cid"; + + private final String candidateId; + + public CandidateUsed(String candidateId) { + this.candidateId = candidateId; + } + + public String getCandidateId() { + return candidateId; + } + + @Override + public String getElementName() { + return ELEMENT; + } + + @Override + public CharSequence toXML() { + XmlStringBuilder xml = new XmlStringBuilder(); + xml.halfOpenElement(this); + xml.attribute(ATTR_CID, candidateId); + xml.closeEmptyElement(); + return xml; + } + + @Override + public boolean equals(Object other) { + return other instanceof CandidateUsed && + ((CandidateUsed) other).getCandidateId().equals(candidateId); + } + + @Override + public int hashCode() { + return toXML().toString().hashCode(); + } + } + + public static final class CandidateError extends JingleS5BTransportInfo { + public static final String ELEMENT = "candidate-error"; + + private CandidateError() { + + } + + @Override + public String getElementName() { + return ELEMENT; + } + + @Override + public CharSequence toXML() { + XmlStringBuilder xml = new XmlStringBuilder(); + xml.halfOpenElement(this); + xml.closeEmptyElement(); + return xml; + } + + @Override + public boolean equals(Object other) { + return other instanceof CandidateError; + } + + @Override + public int hashCode() { + return toXML().toString().hashCode(); + } + } + + public static final class ProxyError extends JingleS5BTransportInfo { + public static final String ELEMENT = "proxy-error"; + + private ProxyError() { + + } + + @Override + public String getElementName() { + return ELEMENT; + } + + @Override + public CharSequence toXML() { + XmlStringBuilder xml = new XmlStringBuilder(); + xml.halfOpenElement(this); + xml.closeEmptyElement(); + return xml; + } + + @Override + public boolean equals(Object other) { + return other instanceof ProxyError; + } + + @Override + public int hashCode() { + return toXML().toString().hashCode(); + } + } +} 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/transports/jingle_s5b/elements/package-info.java new file mode 100644 index 000000000..2a30922f4 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_s5b/elements/package-info.java @@ -0,0 +1,22 @@ +/** + * + * 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. + */ + +/** + * Smack's API for XEP-0260: Jingle SOCKS5 Bytestreams. + * Element classes. + */ +package org.jivesoftware.smackx.jingle.transports.jingle_s5b.elements; 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/transports/jingle_s5b/package-info.java new file mode 100644 index 000000000..4f3ab5356 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_s5b/package-info.java @@ -0,0 +1,21 @@ +/** + * + * 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. + */ + +/** + * Smack's API for XEP-0260: Jingle SOCKS5 Bytestreams. + */ +package org.jivesoftware.smackx.jingle.transports.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/transports/jingle_s5b/provider/JingleS5BTransportProvider.java new file mode 100644 index 000000000..fcd99cfa9 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_s5b/provider/JingleS5BTransportProvider.java @@ -0,0 +1,118 @@ +/** + * + * 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.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.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.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.xmlpull.v1.XmlPullParser; + +/** + * Provider for JingleSocks5BytestreamTransport elements. + */ +public class JingleS5BTransportProvider extends JingleContentTransportProvider { + + @Override + public JingleS5BTransport parse(XmlPullParser parser, int initialDepth) throws Exception { + JingleS5BTransport.Builder builder = JingleS5BTransport.getBuilder(); + + String streamId = parser.getAttributeValue(null, JingleS5BTransport.ATTR_SID); + builder.setStreamId(streamId); + + String dstAddr = parser.getAttributeValue(null, JingleS5BTransport.ATTR_DSTADDR); + builder.setDestinationAddress(dstAddr); + + String mode = parser.getAttributeValue(null, JingleS5BTransport.ATTR_MODE); + if (mode != null) { + builder.setMode(mode.equals(udp.toString()) ? udp : tcp); + } + + JingleS5BTransportCandidate.Builder cb; + outerloop: while (true) { + int tag = parser.nextTag(); + String name = parser.getName(); + switch (tag) { + case START_TAG: { + switch (name) { + + case JingleS5BTransportCandidate.ELEMENT: + cb = JingleS5BTransportCandidate.getBuilder(); + cb.setCandidateId(parser.getAttributeValue(null, ATTR_CID)); + cb.setHost(parser.getAttributeValue(null, ATTR_HOST)); + cb.setJid(parser.getAttributeValue(null, ATTR_JID)); + cb.setPriority(Integer.parseInt(parser.getAttributeValue(null, ATTR_PRIORITY))); + + String portString = parser.getAttributeValue(null, ATTR_PORT); + if (portString != null) { + cb.setPort(Integer.parseInt(portString)); + } + + String typeString = parser.getAttributeValue(null, ATTR_TYPE); + if (typeString != null) { + cb.setType(JingleS5BTransportCandidate.Type.fromString(typeString)); + } + builder.addTransportCandidate(cb.build()); + break; + + case JingleS5BTransportInfo.CandidateActivated.ELEMENT: + builder.addTransportInfo(JingleS5BTransportInfo.CandidateActivated( + parser.getAttributeValue(null, + JingleS5BTransportInfo.CandidateActivated.ATTR_CID))); + break; + + case JingleS5BTransportInfo.CandidateUsed.ELEMENT: + builder.addTransportInfo(JingleS5BTransportInfo.CandidateUsed( + parser.getAttributeValue(null, + JingleS5BTransportInfo.CandidateUsed.ATTR_CID))); + break; + + case JingleS5BTransportInfo.CandidateError.ELEMENT: + builder.addTransportInfo(JingleS5BTransportInfo.CandidateError()); + break; + + case JingleS5BTransportInfo.ProxyError.ELEMENT: + builder.addTransportInfo(JingleS5BTransportInfo.ProxyError()); + break; + } + } + break; + + case END_TAG: { + switch (name) { + case JingleContentTransport.ELEMENT: + break outerloop; + } + } + } + } + return builder.build(); + } +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_s5b/provider/package-info.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_s5b/provider/package-info.java new file mode 100644 index 000000000..9fc08fac4 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_s5b/provider/package-info.java @@ -0,0 +1,22 @@ +/** + * + * 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. + */ + +/** + * Smack's API for XEP-0260: Jingle SOCKS5 Bytestreams. + * Provider classes. + */ +package org.jivesoftware.smackx.jingle.transports.jingle_s5b.provider; 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 new file mode 100644 index 000000000..d6504e4de --- /dev/null +++ b/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/transports/jingle_s5b/JingleS5BTransportTest.java @@ -0,0 +1,164 @@ +/** + * + * 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.assertNull; +import static org.junit.Assert.assertEquals; + +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.impl.JidCreate; + +/** + * 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()); + + JingleS5BTransportCandidate candidate1 = + (JingleS5BTransportCandidate) transport.getCandidates().get(0); + 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()); + assertEquals(1, candidateErrorTransport.getInfos().size()); + assertEquals("vj3hs98y", candidateErrorTransport.getStreamId()); + assertEquals(JingleS5BTransportInfo.CandidateError(), + candidateErrorTransport.getInfos().get(0)); + assertEquals(candidateError, candidateErrorTransport.toXML().toString()); + + String proxyError = + "" + + "" + + ""; + JingleS5BTransport proxyErrorTransport = new JingleS5BTransportProvider() + .parse(TestUtils.getParser(proxyError)); + assertNull(proxyErrorTransport.getDestinationAddress()); + assertEquals(1, proxyErrorTransport.getInfos().size()); + assertEquals("vj3hs98y", proxyErrorTransport.getStreamId()); + assertEquals(JingleS5BTransportInfo.ProxyError(), + proxyErrorTransport.getInfos().get(0)); + assertEquals(proxyError, proxyErrorTransport.toXML().toString()); + + String candidateUsed = + "" + + "" + + ""; + JingleS5BTransport candidateUsedTransport = new JingleS5BTransportProvider() + .parse(TestUtils.getParser(candidateUsed)); + assertEquals(1, candidateUsedTransport.getInfos().size()); + assertEquals(JingleS5BTransportInfo.CandidateUsed("hr65dqyd"), + candidateUsedTransport.getInfos().get(0)); + assertEquals("hr65dqyd", + ((JingleS5BTransportInfo.CandidateUsed) + candidateUsedTransport.getInfos().get(0)).getCandidateId()); + assertEquals(candidateUsed, candidateUsedTransport.toXML().toString()); + + String candidateActivated = + "" + + "" + + ""; + JingleS5BTransport candidateActivatedTransport = new JingleS5BTransportProvider() + .parse(TestUtils.getParser(candidateActivated)); + assertEquals(1, candidateActivatedTransport.getInfos().size()); + assertEquals(JingleS5BTransportInfo.CandidateActivated("hr65dqyd"), + candidateActivatedTransport.getInfos().get(0)); + assertEquals("hr65dqyd", + ((JingleS5BTransportInfo.CandidateActivated) + candidateActivatedTransport.getInfos().get(0)).getCandidateId()); + assertEquals(candidateActivated, candidateActivatedTransport.toXML().toString()); + } +}