001: /*
002: * @(#)SocksSocketImplFactory.java 1.7 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026: package java.net;
027:
028: import java.security.AccessController;
029: import java.security.PrivilegedExceptionAction;
030: import java.io.InputStream;
031: import java.io.OutputStream;
032:
033: /**
034: * This factory creates an SocketImpl that implements the SOCKS protocol
035: * (both V5 & V4). It implements RFC 1928.
036: *
037: * @see java.net.Socket#setSocketImplFactory(SocketImplFactory)
038: * @see java.net.ServerSocket#setSocketImplFactory(SocketImplFactory)
039: */
040:
041: class SocksSocketImplFactory implements SocketImplFactory, SocksConsts {
042: private String server;
043: private int port = -1;
044: private boolean useV4 = false;
045:
046: /**
047: * Creates a SocksSocketImplFactory with a specific server & port.
048: * This should point to a SOCKS v5 proxy server.
049: *
050: * @param server the server hostname
051: * @param port the port number. -1 for the default SOCKS port.
052: */
053: SocksSocketImplFactory(String server, int port) {
054: this .server = server;
055: this .port = port == -1 ? DEFAULT_PORT : port;
056: guessVersion();
057: }
058:
059: /**
060: * Creates a SocksSocketImplFactory with a specific server & port.
061: *
062: * @param server the server hostname
063: * @param port the port number. -1 for the default SOCKS port.
064: * @param v4 <code>true</code> if the protocol should be version 4
065: * <code>false</code> for version 5.
066: */
067: SocksSocketImplFactory(String server, int port, boolean v4) {
068: this .server = server;
069: this .port = port == -1 ? DEFAULT_PORT : port;
070: this .useV4 = v4;
071: }
072:
073: /*
074: * Checks whether the System properties changed.
075: * If they did, we need to renegociate the protocol version
076: */
077:
078: private synchronized void checkProps() {
079: boolean changed = false;
080: int newport = DEFAULT_PORT;
081: String socksPort = null;
082: String socksHost = (String) java.security.AccessController
083: .doPrivileged(new sun.security.action.GetPropertyAction(
084: "socksProxyHost"));
085: socksPort = (String) java.security.AccessController
086: .doPrivileged(new sun.security.action.GetPropertyAction(
087: "socksProxyPort"));
088: if (socksPort != null) {
089: try {
090: newport = Integer.parseInt(socksPort);
091: } catch (Exception e) {
092: newport = DEFAULT_PORT;
093: }
094: }
095: if (socksHost != null && !socksHost.equals(this .server)) {
096: this .server = socksHost;
097: changed = true;
098: }
099: if (newport != this .port) {
100: this .port = newport;
101: changed = true;
102: }
103: if (changed) {
104: guessVersion();
105: }
106: }
107:
108: private void guessVersion() {
109: Socket s;
110: // Connects to the SOCKS server
111:
112: try {
113: s = (Socket) AccessController
114: .doPrivileged(new PrivilegedExceptionAction() {
115: public Object run() throws Exception {
116: Socket so = new Socket(
117: new PlainSocketImpl());
118: so.connect(new InetSocketAddress(server,
119: port));
120: return so;
121: }
122: });
123: } catch (Exception e) {
124: e.printStackTrace();
125: return;
126: }
127: InputStream in = null;
128: OutputStream out = null;
129: try {
130: // If it's taking too long to get an answer, then it's probably
131: // the wrong version
132: s.setSoTimeout(1000);
133: out = s.getOutputStream();
134: in = s.getInputStream();
135: // Try V5 first
136: out.write(PROTO_VERS);
137: out.write(2);
138: out.write(NO_AUTH);
139: out.write(USER_PASSW);
140: out.flush();
141: int i = in.read();
142: if (i == PROTO_VERS) {
143: // All rigth it's V5
144: useV4 = false;
145: i = in.read();
146: } else {
147: // V5 doesn't work, let's assume it's V4
148: useV4 = true;
149: }
150: in.close();
151: out.close();
152: s.close();
153: } catch (java.net.SocketTimeoutException te) {
154: // Timeout. Took too long let's assume it's V4 then
155: useV4 = true;
156: try {
157: in.close();
158: out.close();
159: s.close();
160: } catch (Exception e2) {
161: }
162: } catch (java.io.IOException ioe) {
163: // Nothing much we can do here, but we tried
164: }
165: }
166:
167: /**
168: * Creates a new <code>SocketImpl</code> instance.
169: *
170: * @return a new instance of <code>SocketImpl</code>.
171: * @see java.net.SocketImpl
172: */
173: public SocketImpl createSocketImpl() {
174: checkProps();
175: SocksSocketImpl impl = new SocksSocketImpl(server, port);
176: if (useV4)
177: impl.setV4();
178: return impl;
179: }
180: }
|