1/*
2 * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/MultihomePlainSocketFactory.java $
3 * $Revision: 653041 $
4 * $Date: 2008-05-03 03:39:28 -0700 (Sat, 03 May 2008) $
5 *
6 * ====================================================================
7 * Licensed to the Apache Software Foundation (ASF) under one
8 * or more contributor license agreements.  See the NOTICE file
9 * distributed with this work for additional information
10 * regarding copyright ownership.  The ASF licenses this file
11 * to you under the Apache License, Version 2.0 (the
12 * "License"); you may not use this file except in compliance
13 * with the License.  You may obtain a copy of the License at
14 *
15 *   http://www.apache.org/licenses/LICENSE-2.0
16 *
17 * Unless required by applicable law or agreed to in writing,
18 * software distributed under the License is distributed on an
19 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20 * KIND, either express or implied.  See the License for the
21 * specific language governing permissions and limitations
22 * under the License.
23 * ====================================================================
24 *
25 * This software consists of voluntary contributions made by many
26 * individuals on behalf of the Apache Software Foundation.  For more
27 * information on the Apache Software Foundation, please see
28 * <http://www.apache.org/>.
29 *
30 */
31
32package org.apache.http.conn;
33
34import java.io.IOException;
35import java.net.InetAddress;
36import java.net.InetSocketAddress;
37import java.net.Socket;
38import java.net.SocketTimeoutException;
39import java.util.ArrayList;
40import java.util.Collections;
41import java.util.List;
42import java.util.Arrays;
43
44import org.apache.http.conn.scheme.PlainSocketFactory;
45import org.apache.http.conn.scheme.SocketFactory;
46import org.apache.http.params.HttpConnectionParams;
47import org.apache.http.params.HttpParams;
48
49/**
50 * Socket factory that implements a simple multi-home fail-over on connect failure,
51 * provided the same hostname resolves to multiple {@link InetAddress}es. Please note
52 * the {@link #connectSocket(Socket, String, int, InetAddress, int, HttpParams)}
53 * method cannot be reliably interrupted by closing the socket returned by the
54 * {@link #createSocket()} method.
55 *
56 * @deprecated Please use {@link java.net.URL#openConnection} instead.
57 *     Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
58 *     for further details.
59 */
60@Deprecated
61public final class MultihomePlainSocketFactory implements SocketFactory {
62
63    /**
64     * The factory singleton.
65     */
66    private static final
67    MultihomePlainSocketFactory DEFAULT_FACTORY = new MultihomePlainSocketFactory();
68
69    /**
70     * Gets the singleton instance of this class.
71     * @return the one and only plain socket factory
72     */
73    public static MultihomePlainSocketFactory getSocketFactory() {
74        return DEFAULT_FACTORY;
75    }
76
77    /**
78     * Restricted default constructor.
79     */
80    private MultihomePlainSocketFactory() {
81        super();
82    }
83
84
85    // non-javadoc, see interface org.apache.http.conn.SocketFactory
86    public Socket createSocket() {
87        return new Socket();
88    }
89
90    /**
91     * Attempts to connects the socket to any of the {@link InetAddress}es the
92     * given host name resolves to. If connection to all addresses fail, the
93     * last I/O exception is propagated to the caller.
94     *
95     * @param sock socket to connect to any of the given addresses
96     * @param host Host name to connect to
97     * @param port the port to connect to
98     * @param localAddress local address
99     * @param localPort local port
100     * @param params HTTP parameters
101     *
102     * @throws  IOException if an error occurs during the connection
103     * @throws  SocketTimeoutException if timeout expires before connecting
104     */
105    public Socket connectSocket(Socket sock, String host, int port,
106                                InetAddress localAddress, int localPort,
107                                HttpParams params)
108        throws IOException {
109
110        if (host == null) {
111            throw new IllegalArgumentException("Target host may not be null.");
112        }
113        if (params == null) {
114            throw new IllegalArgumentException("Parameters may not be null.");
115        }
116
117        if (sock == null)
118            sock = createSocket();
119
120        if ((localAddress != null) || (localPort > 0)) {
121
122            // we need to bind explicitly
123            if (localPort < 0)
124                localPort = 0; // indicates "any"
125
126            InetSocketAddress isa =
127                new InetSocketAddress(localAddress, localPort);
128            sock.bind(isa);
129        }
130
131        int timeout = HttpConnectionParams.getConnectionTimeout(params);
132
133        InetAddress[] inetadrs = InetAddress.getAllByName(host);
134        List<InetAddress> addresses = new ArrayList<InetAddress>(inetadrs.length);
135        addresses.addAll(Arrays.asList(inetadrs));
136        Collections.shuffle(addresses);
137
138        IOException lastEx = null;
139        for (InetAddress address: addresses) {
140            try {
141                sock.connect(new InetSocketAddress(address, port), timeout);
142                break;
143            } catch (SocketTimeoutException ex) {
144                throw ex;
145            } catch (IOException ex) {
146                // create new socket
147                sock = new Socket();
148                // keep the last exception and retry
149                lastEx = ex;
150            }
151        }
152        if (lastEx != null) {
153            throw lastEx;
154        }
155        return sock;
156    } // connectSocket
157
158
159    /**
160     * Checks whether a socket connection is secure.
161     * This factory creates plain socket connections
162     * which are not considered secure.
163     *
164     * @param sock      the connected socket
165     *
166     * @return  <code>false</code>
167     *
168     * @throws IllegalArgumentException if the argument is invalid
169     */
170    public final boolean isSecure(Socket sock)
171        throws IllegalArgumentException {
172
173        if (sock == null) {
174            throw new IllegalArgumentException("Socket may not be null.");
175        }
176        // This class check assumes that createSocket() calls the constructor
177        // directly. If it was using javax.net.SocketFactory, we couldn't make
178        // an assumption about the socket class here.
179        if (sock.getClass() != Socket.class) {
180            throw new IllegalArgumentException
181                ("Socket not created by this factory.");
182        }
183        // This check is performed last since it calls a method implemented
184        // by the argument object. getClass() is final in java.lang.Object.
185        if (sock.isClosed()) {
186            throw new IllegalArgumentException("Socket is closed.");
187        }
188
189        return false;
190
191    } // isSecure
192
193
194    /**
195     * Compares this factory with an object.
196     * There is only one instance of this class.
197     *
198     * @param obj       the object to compare with
199     *
200     * @return  iff the argument is this object
201     */
202    @Override
203    public boolean equals(Object obj) {
204        return (obj == this);
205    }
206
207    /**
208     * Obtains a hash code for this object.
209     * All instances of this class have the same hash code.
210     * There is only one instance of this class.
211     */
212    @Override
213    public int hashCode() {
214        return PlainSocketFactory.class.hashCode();
215    }
216
217}
218