aboutsummaryrefslogtreecommitdiff
path: root/src/org/jivesoftware/smackx/bytestreams/socks5/packet/Bytestream.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/org/jivesoftware/smackx/bytestreams/socks5/packet/Bytestream.java')
-rw-r--r--src/org/jivesoftware/smackx/bytestreams/socks5/packet/Bytestream.java474
1 files changed, 474 insertions, 0 deletions
diff --git a/src/org/jivesoftware/smackx/bytestreams/socks5/packet/Bytestream.java b/src/org/jivesoftware/smackx/bytestreams/socks5/packet/Bytestream.java
new file mode 100644
index 0000000..9e07fc3
--- /dev/null
+++ b/src/org/jivesoftware/smackx/bytestreams/socks5/packet/Bytestream.java
@@ -0,0 +1,474 @@
+/**
+ * All rights reserved. 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.bytestreams.socks5.packet;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.packet.PacketExtension;
+
+/**
+ * A packet representing part of a SOCKS5 Bytestream negotiation.
+ *
+ * @author Alexander Wenckus
+ */
+public class Bytestream extends IQ {
+
+ private String sessionID;
+
+ private Mode mode = Mode.tcp;
+
+ private final List<StreamHost> streamHosts = new ArrayList<StreamHost>();
+
+ private StreamHostUsed usedHost;
+
+ private Activate toActivate;
+
+ /**
+ * The default constructor
+ */
+ public Bytestream() {
+ super();
+ }
+
+ /**
+ * A constructor where the session ID can be specified.
+ *
+ * @param SID The session ID related to the negotiation.
+ * @see #setSessionID(String)
+ */
+ public Bytestream(final String SID) {
+ super();
+ setSessionID(SID);
+ }
+
+ /**
+ * Set the session ID related to the bytestream. The session ID is a unique identifier used to
+ * differentiate between stream negotiations.
+ *
+ * @param sessionID the unique session ID that identifies the transfer.
+ */
+ public void setSessionID(final String sessionID) {
+ this.sessionID = sessionID;
+ }
+
+ /**
+ * Returns the session ID related to the bytestream negotiation.
+ *
+ * @return Returns the session ID related to the bytestream negotiation.
+ * @see #setSessionID(String)
+ */
+ public String getSessionID() {
+ return sessionID;
+ }
+
+ /**
+ * Set the transport mode. This should be put in the initiation of the interaction.
+ *
+ * @param mode the transport mode, either UDP or TCP
+ * @see Mode
+ */
+ public void setMode(final Mode mode) {
+ this.mode = mode;
+ }
+
+ /**
+ * Returns the transport mode.
+ *
+ * @return Returns the transport mode.
+ * @see #setMode(Mode)
+ */
+ public Mode getMode() {
+ return mode;
+ }
+
+ /**
+ * Adds a potential stream host that the remote user can connect to to receive the file.
+ *
+ * @param JID The JID of the stream host.
+ * @param address The internet address of the stream host.
+ * @return The added stream host.
+ */
+ public StreamHost addStreamHost(final String JID, final String address) {
+ return addStreamHost(JID, address, 0);
+ }
+
+ /**
+ * Adds a potential stream host that the remote user can connect to to receive the file.
+ *
+ * @param JID The JID of the stream host.
+ * @param address The internet address of the stream host.
+ * @param port The port on which the remote host is seeking connections.
+ * @return The added stream host.
+ */
+ public StreamHost addStreamHost(final String JID, final String address, final int port) {
+ StreamHost host = new StreamHost(JID, address);
+ host.setPort(port);
+ addStreamHost(host);
+
+ return host;
+ }
+
+ /**
+ * Adds a potential stream host that the remote user can transfer the file through.
+ *
+ * @param host The potential stream host.
+ */
+ public void addStreamHost(final StreamHost host) {
+ streamHosts.add(host);
+ }
+
+ /**
+ * Returns the list of stream hosts contained in the packet.
+ *
+ * @return Returns the list of stream hosts contained in the packet.
+ */
+ public Collection<StreamHost> getStreamHosts() {
+ return Collections.unmodifiableCollection(streamHosts);
+ }
+
+ /**
+ * Returns the stream host related to the given JID, or null if there is none.
+ *
+ * @param JID The JID of the desired stream host.
+ * @return Returns the stream host related to the given JID, or null if there is none.
+ */
+ public StreamHost getStreamHost(final String JID) {
+ if (JID == null) {
+ return null;
+ }
+ for (StreamHost host : streamHosts) {
+ if (host.getJID().equals(JID)) {
+ return host;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the count of stream hosts contained in this packet.
+ *
+ * @return Returns the count of stream hosts contained in this packet.
+ */
+ public int countStreamHosts() {
+ return streamHosts.size();
+ }
+
+ /**
+ * Upon connecting to the stream host the target of the stream replies to the initiator with the
+ * JID of the SOCKS5 host that they used.
+ *
+ * @param JID The JID of the used host.
+ */
+ public void setUsedHost(final String JID) {
+ this.usedHost = new StreamHostUsed(JID);
+ }
+
+ /**
+ * Returns the SOCKS5 host connected to by the remote user.
+ *
+ * @return Returns the SOCKS5 host connected to by the remote user.
+ */
+ public StreamHostUsed getUsedHost() {
+ return usedHost;
+ }
+
+ /**
+ * Returns the activate element of the packet sent to the proxy host to verify the identity of
+ * the initiator and match them to the appropriate stream.
+ *
+ * @return Returns the activate element of the packet sent to the proxy host to verify the
+ * identity of the initiator and match them to the appropriate stream.
+ */
+ public Activate getToActivate() {
+ return toActivate;
+ }
+
+ /**
+ * Upon the response from the target of the used host the activate packet is sent to the SOCKS5
+ * proxy. The proxy will activate the stream or return an error after verifying the identity of
+ * the initiator, using the activate packet.
+ *
+ * @param targetID The JID of the target of the file transfer.
+ */
+ public void setToActivate(final String targetID) {
+ this.toActivate = new Activate(targetID);
+ }
+
+ public String getChildElementXML() {
+ StringBuilder buf = new StringBuilder();
+
+ buf.append("<query xmlns=\"http://jabber.org/protocol/bytestreams\"");
+ if (this.getType().equals(IQ.Type.SET)) {
+ if (getSessionID() != null) {
+ buf.append(" sid=\"").append(getSessionID()).append("\"");
+ }
+ if (getMode() != null) {
+ buf.append(" mode = \"").append(getMode()).append("\"");
+ }
+ buf.append(">");
+ if (getToActivate() == null) {
+ for (StreamHost streamHost : getStreamHosts()) {
+ buf.append(streamHost.toXML());
+ }
+ }
+ else {
+ buf.append(getToActivate().toXML());
+ }
+ }
+ else if (this.getType().equals(IQ.Type.RESULT)) {
+ buf.append(">");
+ if (getUsedHost() != null) {
+ buf.append(getUsedHost().toXML());
+ }
+ // A result from the server can also contain stream hosts
+ else if (countStreamHosts() > 0) {
+ for (StreamHost host : streamHosts) {
+ buf.append(host.toXML());
+ }
+ }
+ }
+ else if (this.getType().equals(IQ.Type.GET)) {
+ return buf.append("/>").toString();
+ }
+ else {
+ return null;
+ }
+ buf.append("</query>");
+
+ return buf.toString();
+ }
+
+ /**
+ * Packet extension that represents a potential SOCKS5 proxy for the file transfer. Stream hosts
+ * are forwarded to the target of the file transfer who then chooses and connects to one.
+ *
+ * @author Alexander Wenckus
+ */
+ public static class StreamHost implements PacketExtension {
+
+ public static String NAMESPACE = "";
+
+ public static String ELEMENTNAME = "streamhost";
+
+ private final String JID;
+
+ private final String addy;
+
+ private int port = 0;
+
+ /**
+ * Default constructor.
+ *
+ * @param JID The JID of the stream host.
+ * @param address The internet address of the stream host.
+ */
+ public StreamHost(final String JID, final String address) {
+ this.JID = JID;
+ this.addy = address;
+ }
+
+ /**
+ * Returns the JID of the stream host.
+ *
+ * @return Returns the JID of the stream host.
+ */
+ public String getJID() {
+ return JID;
+ }
+
+ /**
+ * Returns the internet address of the stream host.
+ *
+ * @return Returns the internet address of the stream host.
+ */
+ public String getAddress() {
+ return addy;
+ }
+
+ /**
+ * Sets the port of the stream host.
+ *
+ * @param port The port on which the potential stream host would accept the connection.
+ */
+ public void setPort(final int port) {
+ this.port = port;
+ }
+
+ /**
+ * Returns the port on which the potential stream host would accept the connection.
+ *
+ * @return Returns the port on which the potential stream host would accept the connection.
+ */
+ public int getPort() {
+ return port;
+ }
+
+ public String getNamespace() {
+ return NAMESPACE;
+ }
+
+ public String getElementName() {
+ return ELEMENTNAME;
+ }
+
+ public String toXML() {
+ StringBuilder buf = new StringBuilder();
+
+ buf.append("<").append(getElementName()).append(" ");
+ buf.append("jid=\"").append(getJID()).append("\" ");
+ buf.append("host=\"").append(getAddress()).append("\" ");
+ if (getPort() != 0) {
+ buf.append("port=\"").append(getPort()).append("\"");
+ }
+ else {
+ buf.append("zeroconf=\"_jabber.bytestreams\"");
+ }
+ buf.append("/>");
+
+ return buf.toString();
+ }
+ }
+
+ /**
+ * After selected a SOCKS5 stream host and successfully connecting, the target of the file
+ * transfer returns a byte stream packet with the stream host used extension.
+ *
+ * @author Alexander Wenckus
+ */
+ public static class StreamHostUsed implements PacketExtension {
+
+ public String NAMESPACE = "";
+
+ public static String ELEMENTNAME = "streamhost-used";
+
+ private final String JID;
+
+ /**
+ * Default constructor.
+ *
+ * @param JID The JID of the selected stream host.
+ */
+ public StreamHostUsed(final String JID) {
+ this.JID = JID;
+ }
+
+ /**
+ * Returns the JID of the selected stream host.
+ *
+ * @return Returns the JID of the selected stream host.
+ */
+ public String getJID() {
+ return JID;
+ }
+
+ public String getNamespace() {
+ return NAMESPACE;
+ }
+
+ public String getElementName() {
+ return ELEMENTNAME;
+ }
+
+ public String toXML() {
+ StringBuilder buf = new StringBuilder();
+ buf.append("<").append(getElementName()).append(" ");
+ buf.append("jid=\"").append(getJID()).append("\" ");
+ buf.append("/>");
+ return buf.toString();
+ }
+ }
+
+ /**
+ * The packet sent by the stream initiator to the stream proxy to activate the connection.
+ *
+ * @author Alexander Wenckus
+ */
+ public static class Activate implements PacketExtension {
+
+ public String NAMESPACE = "";
+
+ public static String ELEMENTNAME = "activate";
+
+ private final String target;
+
+ /**
+ * Default constructor specifying the target of the stream.
+ *
+ * @param target The target of the stream.
+ */
+ public Activate(final String target) {
+ this.target = target;
+ }
+
+ /**
+ * Returns the target of the activation.
+ *
+ * @return Returns the target of the activation.
+ */
+ public String getTarget() {
+ return target;
+ }
+
+ public String getNamespace() {
+ return NAMESPACE;
+ }
+
+ public String getElementName() {
+ return ELEMENTNAME;
+ }
+
+ public String toXML() {
+ StringBuilder buf = new StringBuilder();
+ buf.append("<").append(getElementName()).append(">");
+ buf.append(getTarget());
+ buf.append("</").append(getElementName()).append(">");
+ return buf.toString();
+ }
+ }
+
+ /**
+ * The stream can be either a TCP stream or a UDP stream.
+ *
+ * @author Alexander Wenckus
+ */
+ public enum Mode {
+
+ /**
+ * A TCP based stream.
+ */
+ tcp,
+
+ /**
+ * A UDP based stream.
+ */
+ udp;
+
+ public static Mode fromName(String name) {
+ Mode mode;
+ try {
+ mode = Mode.valueOf(name);
+ }
+ catch (Exception ex) {
+ mode = tcp;
+ }
+
+ return mode;
+ }
+ }
+}