/** | |
* 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; | |
} | |
} |