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.Socket;
024    import java.net.UnknownHostException;
025    import java.nio.channels.SocketChannel;
026    
027    import javax.net.SocketFactory;
028    
029    import org.apache.hadoop.classification.InterfaceAudience;
030    import org.apache.hadoop.classification.InterfaceStability;
031    
032    /**
033     * Specialized SocketFactory to create sockets with a SOCKS proxy
034     */
035    @InterfaceAudience.Public
036    @InterfaceStability.Evolving
037    public class StandardSocketFactory extends SocketFactory {
038    
039      /**
040       * Default empty constructor (for use with the reflection API).
041       */
042      public StandardSocketFactory() {
043      }
044    
045      /* @inheritDoc */
046      @Override
047      public Socket createSocket() throws IOException {
048        /*
049         * NOTE: This returns an NIO socket so that it has an associated 
050         * SocketChannel. As of now, this unfortunately makes streams returned
051         * by Socket.getInputStream() and Socket.getOutputStream() unusable
052         * (because a blocking read on input stream blocks write on output stream
053         * and vice versa).
054         * 
055         * So users of these socket factories should use 
056         * NetUtils.getInputStream(socket) and 
057         * NetUtils.getOutputStream(socket) instead.
058         * 
059         * A solution for hiding from this from user is to write a 
060         * 'FilterSocket' on the lines of FilterInputStream and extend it by
061         * overriding getInputStream() and getOutputStream().
062         */
063        return SocketChannel.open().socket();
064      }
065    
066      /* @inheritDoc */
067      @Override
068      public Socket createSocket(InetAddress addr, int port) throws IOException {
069    
070        Socket socket = createSocket();
071        socket.connect(new InetSocketAddress(addr, port));
072        return socket;
073      }
074    
075      /* @inheritDoc */
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      /* @inheritDoc */
087      @Override
088      public Socket createSocket(String host, int port) throws IOException,
089          UnknownHostException {
090    
091        Socket socket = createSocket();
092        socket.connect(new InetSocketAddress(host, port));
093        return socket;
094      }
095    
096      /* @inheritDoc */
097      @Override
098      public Socket createSocket(String host, int port,
099          InetAddress localHostAddr, int localPort) throws IOException,
100          UnknownHostException {
101    
102        Socket socket = createSocket();
103        socket.bind(new InetSocketAddress(localHostAddr, localPort));
104        socket.connect(new InetSocketAddress(host, port));
105        return socket;
106      }
107    
108      /* @inheritDoc */
109      @Override
110      public boolean equals(Object obj) {
111        if (this == obj)
112          return true;
113        if (obj == null)
114          return false;
115        return obj.getClass().equals(this.getClass());
116      }
117    
118      /* @inheritDoc */
119      @Override
120      public int hashCode() {
121        return this.getClass().hashCode();
122      }
123    
124    }