/** * 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; import java.io.IOException; import java.net.Socket; import java.util.concurrent.TimeoutException; import org.jivesoftware.smack.Connection; import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.packet.IQ; import org.jivesoftware.smack.util.SyncPacketSend; import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream; import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream.StreamHost; /** * Implementation of a SOCKS5 client used on the initiators side. This is needed because connecting * to the local SOCKS5 proxy differs form the regular way to connect to a SOCKS5 proxy. Additionally * a remote SOCKS5 proxy has to be activated by the initiator before data can be transferred between * the peers. * * @author Henning Staib */ class Socks5ClientForInitiator extends Socks5Client { /* the XMPP connection used to communicate with the SOCKS5 proxy */ private Connection connection; /* the session ID used to activate SOCKS5 stream */ private String sessionID; /* the target JID used to activate SOCKS5 stream */ private String target; /** * Creates a new SOCKS5 client for the initiators side. * * @param streamHost containing network settings of the SOCKS5 proxy * @param digest identifying the SOCKS5 Bytestream * @param connection the XMPP connection * @param sessionID the session ID of the SOCKS5 Bytestream * @param target the target JID of the SOCKS5 Bytestream */ public Socks5ClientForInitiator(StreamHost streamHost, String digest, Connection connection, String sessionID, String target) { super(streamHost, digest); this.connection = connection; this.sessionID = sessionID; this.target = target; } public Socket getSocket(int timeout) throws IOException, XMPPException, InterruptedException, TimeoutException { Socket socket = null; // check if stream host is the local SOCKS5 proxy if (this.streamHost.getJID().equals(this.connection.getUser())) { Socks5Proxy socks5Server = Socks5Proxy.getSocks5Proxy(); socket = socks5Server.getSocket(this.digest); if (socket == null) { throw new XMPPException("target is not connected to SOCKS5 proxy"); } } else { socket = super.getSocket(timeout); try { activate(); } catch (XMPPException e) { socket.close(); throw new XMPPException("activating SOCKS5 Bytestream failed", e); } } return socket; } /** * Activates the SOCKS5 Bytestream by sending a XMPP SOCKS5 Bytestream activation packet to the * SOCKS5 proxy. */ private void activate() throws XMPPException { Bytestream activate = createStreamHostActivation(); // if activation fails #getReply throws an exception SyncPacketSend.getReply(this.connection, activate); } /** * Returns a SOCKS5 Bytestream activation packet. * * @return SOCKS5 Bytestream activation packet */ private Bytestream createStreamHostActivation() { Bytestream activate = new Bytestream(this.sessionID); activate.setMode(null); activate.setType(IQ.Type.SET); activate.setTo(this.streamHost.getJID()); activate.setToActivate(this.target); return activate; } }