001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements.  See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership.  The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the
007     * "License"); you may not use this file except in compliance
008     * with the License.  You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    package org.apache.hadoop.net;
019    
020    import java.io.IOException;
021    import java.net.InetAddress;
022    import java.net.InetSocketAddress;
023    import java.net.Proxy;
024    import java.net.Socket;
025    import java.net.UnknownHostException;
026    
027    import javax.net.SocketFactory;
028    
029    import org.apache.hadoop.classification.InterfaceAudience;
030    import org.apache.hadoop.classification.InterfaceStability;
031    import org.apache.hadoop.conf.Configurable;
032    import org.apache.hadoop.conf.Configuration;
033    
034    /**
035     * Specialized SocketFactory to create sockets with a SOCKS proxy
036     */
037    @InterfaceAudience.Public
038    @InterfaceStability.Evolving
039    public class SocksSocketFactory extends SocketFactory implements
040        Configurable {
041    
042      private Configuration conf;
043    
044      private Proxy proxy;
045    
046      /**
047       * Default empty constructor (for use with the reflection API).
048       */
049      public SocksSocketFactory() {
050        this.proxy = Proxy.NO_PROXY;
051      }
052    
053      /**
054       * Constructor with a supplied Proxy
055       * 
056       * @param proxy the proxy to use to create sockets
057       */
058      public SocksSocketFactory(Proxy proxy) {
059        this.proxy = proxy;
060      }
061    
062      @Override
063      public Socket createSocket() throws IOException {
064    
065        return new Socket(proxy);
066      }
067    
068      @Override
069      public Socket createSocket(InetAddress addr, int port) throws IOException {
070    
071        Socket socket = createSocket();
072        socket.connect(new InetSocketAddress(addr, port));
073        return socket;
074      }
075    
076      @Override
077      public Socket createSocket(InetAddress addr, int port,
078          InetAddress localHostAddr, int localPort) throws IOException {
079    
080        Socket socket = createSocket();
081        socket.bind(new InetSocketAddress(localHostAddr, localPort));
082        socket.connect(new InetSocketAddress(addr, port));
083        return socket;
084      }
085    
086      @Override
087      public Socket createSocket(String host, int port) throws IOException,
088          UnknownHostException {
089    
090        Socket socket = createSocket();
091        socket.connect(new InetSocketAddress(host, port));
092        return socket;
093      }
094    
095      @Override
096      public Socket createSocket(String host, int port,
097          InetAddress localHostAddr, int localPort) throws IOException,
098          UnknownHostException {
099    
100        Socket socket = createSocket();
101        socket.bind(new InetSocketAddress(localHostAddr, localPort));
102        socket.connect(new InetSocketAddress(host, port));
103        return socket;
104      }
105    
106      @Override
107      public int hashCode() {
108        return proxy.hashCode();
109      }
110    
111      @Override
112      public boolean equals(Object obj) {
113        if (this == obj)
114          return true;
115        if (obj == null)
116          return false;
117        if (!(obj instanceof SocksSocketFactory))
118          return false;
119        final SocksSocketFactory other = (SocksSocketFactory) obj;
120        if (proxy == null) {
121          if (other.proxy != null)
122            return false;
123        } else if (!proxy.equals(other.proxy))
124          return false;
125        return true;
126      }
127    
128      @Override
129      public Configuration getConf() {
130        return this.conf;
131      }
132    
133      @Override
134      public void setConf(Configuration conf) {
135        this.conf = conf;
136        String proxyStr = conf.get("hadoop.socks.server");
137        if ((proxyStr != null) && (proxyStr.length() > 0)) {
138          setProxy(proxyStr);
139        }
140      }
141    
142      /**
143       * Set the proxy of this socket factory as described in the string
144       * parameter
145       * 
146       * @param proxyStr the proxy address using the format "host:port"
147       */
148      private void setProxy(String proxyStr) {
149        String[] strs = proxyStr.split(":", 2);
150        if (strs.length != 2)
151          throw new RuntimeException("Bad SOCKS proxy parameter: " + proxyStr);
152        String host = strs[0];
153        int port = Integer.parseInt(strs[1]);
154        this.proxy =
155            new Proxy(Proxy.Type.SOCKS, InetSocketAddress.createUnresolved(host,
156                port));
157      }
158    }