Socks5ClientForInitiator.java

  1. /**
  2.  *
  3.  * Copyright the original author or authors
  4.  *
  5.  * Licensed under the Apache License, Version 2.0 (the "License");
  6.  * you may not use this file except in compliance with the License.
  7.  * You may obtain a copy of the License at
  8.  *
  9.  *     http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.jivesoftware.smackx.bytestreams.socks5;

  18. import java.io.IOException;
  19. import java.net.Socket;
  20. import java.util.concurrent.TimeoutException;

  21. import org.jivesoftware.smack.SmackException;
  22. import org.jivesoftware.smack.SmackException.NoResponseException;
  23. import org.jivesoftware.smack.SmackException.NotConnectedException;
  24. import org.jivesoftware.smack.XMPPConnection;
  25. import org.jivesoftware.smack.XMPPException;
  26. import org.jivesoftware.smack.XMPPException.XMPPErrorException;
  27. import org.jivesoftware.smack.packet.IQ;
  28. import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream;
  29. import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream.StreamHost;
  30. import org.jxmpp.jid.Jid;

  31. /**
  32.  * Implementation of a SOCKS5 client used on the initiators side. This is needed because connecting
  33.  * to the local SOCKS5 proxy differs form the regular way to connect to a SOCKS5 proxy. Additionally
  34.  * a remote SOCKS5 proxy has to be activated by the initiator before data can be transferred between
  35.  * the peers.
  36.  *
  37.  * @author Henning Staib
  38.  */
  39. class Socks5ClientForInitiator extends Socks5Client {

  40.     /* the XMPP connection used to communicate with the SOCKS5 proxy */
  41.     private XMPPConnection connection;

  42.     /* the session ID used to activate SOCKS5 stream */
  43.     private String sessionID;

  44.     /* the target JID used to activate SOCKS5 stream */
  45.     // TODO fullJid?
  46.     private final Jid target;

  47.     /**
  48.      * Creates a new SOCKS5 client for the initiators side.
  49.      *
  50.      * @param streamHost containing network settings of the SOCKS5 proxy
  51.      * @param digest identifying the SOCKS5 Bytestream
  52.      * @param connection the XMPP connection
  53.      * @param sessionID the session ID of the SOCKS5 Bytestream
  54.      * @param target the target JID of the SOCKS5 Bytestream
  55.      */
  56.     public Socks5ClientForInitiator(StreamHost streamHost, String digest, XMPPConnection connection,
  57.                     String sessionID, Jid target) {
  58.         super(streamHost, digest);
  59.         this.connection = connection;
  60.         this.sessionID = sessionID;
  61.         this.target = target;
  62.     }

  63.     public Socket getSocket(int timeout) throws IOException, InterruptedException,
  64.                     TimeoutException, XMPPException, SmackException {
  65.         Socket socket = null;

  66.         // check if stream host is the local SOCKS5 proxy
  67.         if (this.streamHost.getJID().equals(this.connection.getUser())) {
  68.             Socks5Proxy socks5Server = Socks5Proxy.getSocks5Proxy();
  69.             socket = socks5Server.getSocket(this.digest);
  70.             if (socket == null) {
  71.                 throw new SmackException("target is not connected to SOCKS5 proxy");
  72.             }
  73.         }
  74.         else {
  75.             socket = super.getSocket(timeout);

  76.             try {
  77.                 activate();
  78.             }
  79.             catch (XMPPException e1) {
  80.                 socket.close();
  81.                 throw e1;
  82.             }
  83.             catch (NoResponseException e2) {
  84.                 socket.close();
  85.                 throw e2;
  86.             }

  87.         }

  88.         return socket;
  89.     }

  90.     /**
  91.      * Activates the SOCKS5 Bytestream by sending an XMPP SOCKS5 Bytestream activation packet to the
  92.      * SOCKS5 proxy.
  93.      * @throws XMPPErrorException
  94.      * @throws NoResponseException
  95.      * @throws NotConnectedException
  96.      * @throws InterruptedException
  97.      * @throws SmackException if there was no response from the server.
  98.      */
  99.     private void activate() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
  100.         Bytestream activate = createStreamHostActivation();
  101.         // if activation fails #nextResultOrThrow() throws an exception
  102.         connection.createPacketCollectorAndSend(activate).nextResultOrThrow();
  103.     }

  104.     /**
  105.      * Returns a SOCKS5 Bytestream activation packet.
  106.      *
  107.      * @return SOCKS5 Bytestream activation packet
  108.      */
  109.     private Bytestream createStreamHostActivation() {
  110.         Bytestream activate = new Bytestream(this.sessionID);
  111.         activate.setMode(null);
  112.         activate.setType(IQ.Type.set);
  113.         activate.setTo(this.streamHost.getJID());

  114.         activate.setToActivate(this.target);

  115.         return activate;
  116.     }

  117. }