aboutsummaryrefslogtreecommitdiff
path: root/src/org/jivesoftware/smackx/bytestreams/socks5/Socks5ClientForInitiator.java
blob: 0d90791a97f83281136b81812d84afdd59a52a8e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/**
 * 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;
    }

}