• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
32 package org.apache.http.conn;
33 
34 import java.io.IOException;
35 import java.net.InetAddress;
36 import java.net.InetSocketAddress;
37 import java.net.Socket;
38 import java.net.SocketTimeoutException;
39 import java.util.ArrayList;
40 import java.util.Collections;
41 import java.util.List;
42 import java.util.Arrays;
43 
44 import org.apache.http.conn.scheme.PlainSocketFactory;
45 import org.apache.http.conn.scheme.SocketFactory;
46 import org.apache.http.params.HttpConnectionParams;
47 import 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 public final class MultihomePlainSocketFactory implements SocketFactory {
57 
58     /**
59      * The factory singleton.
60      */
61     private static final
62     MultihomePlainSocketFactory DEFAULT_FACTORY = new MultihomePlainSocketFactory();
63 
64     /**
65      * Gets the singleton instance of this class.
66      * @return the one and only plain socket factory
67      */
getSocketFactory()68     public static MultihomePlainSocketFactory getSocketFactory() {
69         return DEFAULT_FACTORY;
70     }
71 
72     /**
73      * Restricted default constructor.
74      */
MultihomePlainSocketFactory()75     private MultihomePlainSocketFactory() {
76         super();
77     }
78 
79 
80     // non-javadoc, see interface org.apache.http.conn.SocketFactory
createSocket()81     public Socket createSocket() {
82         return new Socket();
83     }
84 
85     /**
86      * Attempts to connects the socket to any of the {@link InetAddress}es the
87      * given host name resolves to. If connection to all addresses fail, the
88      * last I/O exception is propagated to the caller.
89      *
90      * @param sock socket to connect to any of the given addresses
91      * @param host Host name to connect to
92      * @param port the port to connect to
93      * @param localAddress local address
94      * @param localPort local port
95      * @param params HTTP parameters
96      *
97      * @throws  IOException if an error occurs during the connection
98      * @throws  SocketTimeoutException if timeout expires before connecting
99      */
connectSocket(Socket sock, String host, int port, InetAddress localAddress, int localPort, HttpParams params)100     public Socket connectSocket(Socket sock, String host, int port,
101                                 InetAddress localAddress, int localPort,
102                                 HttpParams params)
103         throws IOException {
104 
105         if (host == null) {
106             throw new IllegalArgumentException("Target host may not be null.");
107         }
108         if (params == null) {
109             throw new IllegalArgumentException("Parameters may not be null.");
110         }
111 
112         if (sock == null)
113             sock = createSocket();
114 
115         if ((localAddress != null) || (localPort > 0)) {
116 
117             // we need to bind explicitly
118             if (localPort < 0)
119                 localPort = 0; // indicates "any"
120 
121             InetSocketAddress isa =
122                 new InetSocketAddress(localAddress, localPort);
123             sock.bind(isa);
124         }
125 
126         int timeout = HttpConnectionParams.getConnectionTimeout(params);
127 
128         InetAddress[] inetadrs = InetAddress.getAllByName(host);
129         List<InetAddress> addresses = new ArrayList<InetAddress>(inetadrs.length);
130         addresses.addAll(Arrays.asList(inetadrs));
131         Collections.shuffle(addresses);
132 
133         IOException lastEx = null;
134         for (InetAddress address: addresses) {
135             try {
136                 sock.connect(new InetSocketAddress(address, port), timeout);
137                 break;
138             } catch (SocketTimeoutException ex) {
139                 throw ex;
140             } catch (IOException ex) {
141                 // create new socket
142                 sock = new Socket();
143                 // keep the last exception and retry
144                 lastEx = ex;
145             }
146         }
147         if (lastEx != null) {
148             throw lastEx;
149         }
150         return sock;
151     } // connectSocket
152 
153 
154     /**
155      * Checks whether a socket connection is secure.
156      * This factory creates plain socket connections
157      * which are not considered secure.
158      *
159      * @param sock      the connected socket
160      *
161      * @return  <code>false</code>
162      *
163      * @throws IllegalArgumentException if the argument is invalid
164      */
isSecure(Socket sock)165     public final boolean isSecure(Socket sock)
166         throws IllegalArgumentException {
167 
168         if (sock == null) {
169             throw new IllegalArgumentException("Socket may not be null.");
170         }
171         // This class check assumes that createSocket() calls the constructor
172         // directly. If it was using javax.net.SocketFactory, we couldn't make
173         // an assumption about the socket class here.
174         if (sock.getClass() != Socket.class) {
175             throw new IllegalArgumentException
176                 ("Socket not created by this factory.");
177         }
178         // This check is performed last since it calls a method implemented
179         // by the argument object. getClass() is final in java.lang.Object.
180         if (sock.isClosed()) {
181             throw new IllegalArgumentException("Socket is closed.");
182         }
183 
184         return false;
185 
186     } // isSecure
187 
188 
189     /**
190      * Compares this factory with an object.
191      * There is only one instance of this class.
192      *
193      * @param obj       the object to compare with
194      *
195      * @return  iff the argument is this object
196      */
197     @Override
equals(Object obj)198     public boolean equals(Object obj) {
199         return (obj == this);
200     }
201 
202     /**
203      * Obtains a hash code for this object.
204      * All instances of this class have the same hash code.
205      * There is only one instance of this class.
206      */
207     @Override
hashCode()208     public int hashCode() {
209         return PlainSocketFactory.class.hashCode();
210     }
211 
212 }
213