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      /* @inheritDoc */
063      @Override
064      public Socket createSocket() throws IOException {
065    
066        return new Socket(proxy);
067      }
068    
069      /* @inheritDoc */
070      @Override
071      public Socket createSocket(InetAddress addr, int port) throws IOException {
072    
073        Socket socket = createSocket();
074        socket.connect(new InetSocketAddress(addr, port));
075        return socket;
076      }
077    
078      /* @inheritDoc */
079      @Override
080      public Socket createSocket(InetAddress addr, int port,
081          InetAddress localHostAddr, int localPort) throws IOException {
082    
083        Socket socket = createSocket();
084        socket.bind(new InetSocketAddress(localHostAddr, localPort));
085        socket.connect(new InetSocketAddress(addr, port));
086        return socket;
087      }
088    
089      /* @inheritDoc */
090      @Override
091      public Socket createSocket(String host, int port) throws IOException,
092          UnknownHostException {
093    
094        Socket socket = createSocket();
095        socket.connect(new InetSocketAddress(host, port));
096        return socket;
097      }
098    
099      /* @inheritDoc */
100      @Override
101      public Socket createSocket(String host, int port,
102          InetAddress localHostAddr, int localPort) throws IOException,
103          UnknownHostException {
104    
105        Socket socket = createSocket();
106        socket.bind(new InetSocketAddress(localHostAddr, localPort));
107        socket.connect(new InetSocketAddress(host, port));
108        return socket;
109      }
110    
111      /* @inheritDoc */
112      @Override
113      public int hashCode() {
114        return proxy.hashCode();
115      }
116    
117      /* @inheritDoc */
118      @Override
119      public boolean equals(Object obj) {
120        if (this == obj)
121          return true;
122        if (obj == null)
123          return false;
124        if (!(obj instanceof SocksSocketFactory))
125          return false;
126        final SocksSocketFactory other = (SocksSocketFactory) obj;
127        if (proxy == null) {
128          if (other.proxy != null)
129            return false;
130        } else if (!proxy.equals(other.proxy))
131          return false;
132        return true;
133      }
134    
135      /* @inheritDoc */
136      public Configuration getConf() {
137        return this.conf;
138      }
139    
140      /* @inheritDoc */
141      public void setConf(Configuration conf) {
142        this.conf = conf;
143        String proxyStr = conf.get("hadoop.socks.server");
144        if ((proxyStr != null) && (proxyStr.length() > 0)) {
145          setProxy(proxyStr);
146        }
147      }
148    
149      /**
150       * Set the proxy of this socket factory as described in the string
151       * parameter
152       * 
153       * @param proxyStr the proxy address using the format "host:port"
154       */
155      private void setProxy(String proxyStr) {
156        String[] strs = proxyStr.split(":", 2);
157        if (strs.length != 2)
158          throw new RuntimeException("Bad SOCKS proxy parameter: " + proxyStr);
159        String host = strs[0];
160        int port = Integer.parseInt(strs[1]);
161        this.proxy =
162            new Proxy(Proxy.Type.SOCKS, InetSocketAddress.createUnresolved(host,
163                port));
164      }
165    }