blob: 0d90791a97f83281136b81812d84afdd59a52a8e [file] [log] [blame]
Shuyi Chend7955ce2013-05-22 14:51:55 -07001/**
2 * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
3 * you may not use this file except in compliance with the License.
4 * You may obtain a copy of the License at
5 *
6 * http://www.apache.org/licenses/LICENSE-2.0
7 *
8 * Unless required by applicable law or agreed to in writing, software
9 * distributed under the License is distributed on an "AS IS" BASIS,
10 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 * See the License for the specific language governing permissions and
12 * limitations under the License.
13 */
14package org.jivesoftware.smackx.bytestreams.socks5;
15
16import java.io.IOException;
17import java.net.Socket;
18import java.util.concurrent.TimeoutException;
19
20import org.jivesoftware.smack.Connection;
21import org.jivesoftware.smack.XMPPException;
22import org.jivesoftware.smack.packet.IQ;
23import org.jivesoftware.smack.util.SyncPacketSend;
24import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream;
25import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream.StreamHost;
26
27/**
28 * Implementation of a SOCKS5 client used on the initiators side. This is needed because connecting
29 * to the local SOCKS5 proxy differs form the regular way to connect to a SOCKS5 proxy. Additionally
30 * a remote SOCKS5 proxy has to be activated by the initiator before data can be transferred between
31 * the peers.
32 *
33 * @author Henning Staib
34 */
35class Socks5ClientForInitiator extends Socks5Client {
36
37 /* the XMPP connection used to communicate with the SOCKS5 proxy */
38 private Connection connection;
39
40 /* the session ID used to activate SOCKS5 stream */
41 private String sessionID;
42
43 /* the target JID used to activate SOCKS5 stream */
44 private String target;
45
46 /**
47 * Creates a new SOCKS5 client for the initiators side.
48 *
49 * @param streamHost containing network settings of the SOCKS5 proxy
50 * @param digest identifying the SOCKS5 Bytestream
51 * @param connection the XMPP connection
52 * @param sessionID the session ID of the SOCKS5 Bytestream
53 * @param target the target JID of the SOCKS5 Bytestream
54 */
55 public Socks5ClientForInitiator(StreamHost streamHost, String digest, Connection connection,
56 String sessionID, String target) {
57 super(streamHost, digest);
58 this.connection = connection;
59 this.sessionID = sessionID;
60 this.target = target;
61 }
62
63 public Socket getSocket(int timeout) throws IOException, XMPPException, InterruptedException,
64 TimeoutException {
65 Socket socket = null;
66
67 // check if stream host is the local SOCKS5 proxy
68 if (this.streamHost.getJID().equals(this.connection.getUser())) {
69 Socks5Proxy socks5Server = Socks5Proxy.getSocks5Proxy();
70 socket = socks5Server.getSocket(this.digest);
71 if (socket == null) {
72 throw new XMPPException("target is not connected to SOCKS5 proxy");
73 }
74 }
75 else {
76 socket = super.getSocket(timeout);
77
78 try {
79 activate();
80 }
81 catch (XMPPException e) {
82 socket.close();
83 throw new XMPPException("activating SOCKS5 Bytestream failed", e);
84 }
85
86 }
87
88 return socket;
89 }
90
91 /**
92 * Activates the SOCKS5 Bytestream by sending a XMPP SOCKS5 Bytestream activation packet to the
93 * SOCKS5 proxy.
94 */
95 private void activate() throws XMPPException {
96 Bytestream activate = createStreamHostActivation();
97 // if activation fails #getReply throws an exception
98 SyncPacketSend.getReply(this.connection, activate);
99 }
100
101 /**
102 * Returns a SOCKS5 Bytestream activation packet.
103 *
104 * @return SOCKS5 Bytestream activation packet
105 */
106 private Bytestream createStreamHostActivation() {
107 Bytestream activate = new Bytestream(this.sessionID);
108 activate.setMode(null);
109 activate.setType(IQ.Type.SET);
110 activate.setTo(this.streamHost.getJID());
111
112 activate.setToActivate(this.target);
113
114 return activate;
115 }
116
117}