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