1 /* 2 * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/conn/DefaultClientConnectionOperator.java $ 3 * $Revision: 652193 $ 4 * $Date: 2008-04-29 17:10:36 -0700 (Tue, 29 Apr 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.impl.conn; 33 34 import java.io.IOException; 35 import java.net.ConnectException; 36 import java.net.Socket; 37 import java.net.InetAddress; 38 39 import java.net.SocketException; 40 import org.apache.http.HttpHost; 41 import org.apache.http.params.HttpParams; 42 import org.apache.http.params.HttpConnectionParams; 43 import org.apache.http.protocol.HttpContext; 44 45 import org.apache.http.conn.HttpHostConnectException; 46 import org.apache.http.conn.OperatedClientConnection; 47 import org.apache.http.conn.ClientConnectionOperator; 48 import org.apache.http.conn.ConnectTimeoutException; 49 import org.apache.http.conn.scheme.LayeredSocketFactory; 50 import org.apache.http.conn.scheme.PlainSocketFactory; 51 import org.apache.http.conn.scheme.Scheme; 52 import org.apache.http.conn.scheme.SchemeRegistry; 53 import org.apache.http.conn.scheme.SocketFactory; 54 55 56 /** 57 * Default implementation of a 58 * {@link ClientConnectionOperator ClientConnectionOperator}. 59 * It uses a {@link SchemeRegistry SchemeRegistry} to look up 60 * {@link SocketFactory SocketFactory} objects. 61 * 62 * @author <a href="mailto:rolandw at apache.org">Roland Weber</a> 63 * 64 * 65 * <!-- empty lines to avoid svn diff problems --> 66 * @version $Revision: 652193 $ $Date: 2008-04-29 17:10:36 -0700 (Tue, 29 Apr 2008) $ 67 * 68 * @since 4.0 69 */ 70 public class DefaultClientConnectionOperator 71 implements ClientConnectionOperator { 72 73 private static final PlainSocketFactory staticPlainSocketFactory = new PlainSocketFactory(); 74 75 /** The scheme registry for looking up socket factories. */ 76 protected SchemeRegistry schemeRegistry; 77 78 79 /** 80 * Creates a new client connection operator for the given scheme registry. 81 * 82 * @param schemes the scheme registry 83 */ 84 public DefaultClientConnectionOperator(SchemeRegistry schemes) { 85 if (schemes == null) { 86 throw new IllegalArgumentException 87 ("Scheme registry must not be null."); 88 } 89 schemeRegistry = schemes; 90 } 91 92 93 // non-javadoc, see interface ClientConnectionOperator 94 public OperatedClientConnection createConnection() { 95 return new DefaultClientConnection(); 96 } 97 98 99 // non-javadoc, see interface ClientConnectionOperator 100 public void openConnection(OperatedClientConnection conn, 101 HttpHost target, 102 InetAddress local, 103 HttpContext context, 104 HttpParams params) 105 throws IOException { 106 107 if (conn == null) { 108 throw new IllegalArgumentException 109 ("Connection must not be null."); 110 } 111 if (target == null) { 112 throw new IllegalArgumentException 113 ("Target host must not be null."); 114 } 115 // local address may be null 116 //@@@ is context allowed to be null? 117 if (params == null) { 118 throw new IllegalArgumentException 119 ("Parameters must not be null."); 120 } 121 if (conn.isOpen()) { 122 throw new IllegalArgumentException 123 ("Connection must not be open."); 124 } 125 126 final Scheme schm = schemeRegistry.getScheme(target.getSchemeName()); 127 final SocketFactory sf = schm.getSocketFactory(); 128 final SocketFactory plain_sf; 129 final LayeredSocketFactory layered_sf; 130 if (sf instanceof LayeredSocketFactory) { 131 plain_sf = staticPlainSocketFactory; 132 layered_sf = (LayeredSocketFactory)sf; 133 } else { 134 plain_sf = sf; 135 layered_sf = null; 136 } 137 InetAddress[] addresses = InetAddress.getAllByName(target.getHostName()); 138 139 for (int i = 0; i < addresses.length; ++i) { 140 Socket sock = plain_sf.createSocket(); 141 conn.opening(sock, target); 142 143 try { 144 Socket connsock = plain_sf.connectSocket(sock, 145 addresses[i].getHostAddress(), 146 schm.resolvePort(target.getPort()), 147 local, 0, params); 148 if (sock != connsock) { 149 sock = connsock; 150 conn.opening(sock, target); 151 } 152 /* 153 * prepareSocket is called on the just connected 154 * socket before the creation of the layered socket to 155 * ensure that desired socket options such as 156 * TCP_NODELAY, SO_RCVTIMEO, SO_LINGER will be set 157 * before any I/O is performed on the socket. This 158 * happens in the common case as 159 * SSLSocketFactory.createSocket performs hostname 160 * verification which requires that SSL handshaking be 161 * performed. 162 */ 163 prepareSocket(sock, context, params); 164 if (layered_sf != null) { 165 Socket layeredsock = layered_sf.createSocket(sock, 166 target.getHostName(), 167 schm.resolvePort(target.getPort()), 168 true); 169 if (layeredsock != sock) { 170 conn.opening(layeredsock, target); 171 } 172 conn.openCompleted(sf.isSecure(layeredsock), params); 173 } else { 174 conn.openCompleted(sf.isSecure(sock), params); 175 } 176 break; 177 // BEGIN android-changed 178 // catch SocketException to cover any kind of connect failure 179 } catch (SocketException ex) { 180 if (i == addresses.length - 1) { 181 ConnectException cause = ex instanceof ConnectException 182 ? (ConnectException) ex : new ConnectException(ex.getMessage(), ex); 183 throw new HttpHostConnectException(target, cause); 184 } 185 // END android-changed 186 } catch (ConnectTimeoutException ex) { 187 if (i == addresses.length - 1) { 188 throw ex; 189 } 190 } 191 } 192 } // openConnection 193 194 195 // non-javadoc, see interface ClientConnectionOperator 196 public void updateSecureConnection(OperatedClientConnection conn, 197 HttpHost target, 198 HttpContext context, 199 HttpParams params) 200 throws IOException { 201 202 203 if (conn == null) { 204 throw new IllegalArgumentException 205 ("Connection must not be null."); 206 } 207 if (target == null) { 208 throw new IllegalArgumentException 209 ("Target host must not be null."); 210 } 211 //@@@ is context allowed to be null? 212 if (params == null) { 213 throw new IllegalArgumentException 214 ("Parameters must not be null."); 215 } 216 if (!conn.isOpen()) { 217 throw new IllegalArgumentException 218 ("Connection must be open."); 219 } 220 221 final Scheme schm = schemeRegistry.getScheme(target.getSchemeName()); 222 if (!(schm.getSocketFactory() instanceof LayeredSocketFactory)) { 223 throw new IllegalArgumentException 224 ("Target scheme (" + schm.getName() + 225 ") must have layered socket factory."); 226 } 227 228 final LayeredSocketFactory lsf = (LayeredSocketFactory) schm.getSocketFactory(); 229 final Socket sock; 230 try { 231 sock = lsf.createSocket 232 (conn.getSocket(), target.getHostName(), schm.resolvePort(target.getPort()), true); 233 } catch (ConnectException ex) { 234 throw new HttpHostConnectException(target, ex); 235 } 236 prepareSocket(sock, context, params); 237 conn.update(sock, target, lsf.isSecure(sock), params); 238 //@@@ error handling: close the layered socket in case of exception? 239 240 } // updateSecureConnection 241 242 243 /** 244 * Performs standard initializations on a newly created socket. 245 * 246 * @param sock the socket to prepare 247 * @param context the context for the connection 248 * @param params the parameters from which to prepare the socket 249 * 250 * @throws IOException in case of an IO problem 251 */ 252 protected void prepareSocket(Socket sock, HttpContext context, 253 HttpParams params) 254 throws IOException { 255 256 // context currently not used, but derived classes may need it 257 //@@@ is context allowed to be null? 258 259 sock.setTcpNoDelay(HttpConnectionParams.getTcpNoDelay(params)); 260 sock.setSoTimeout(HttpConnectionParams.getSoTimeout(params)); 261 262 int linger = HttpConnectionParams.getLinger(params); 263 if (linger >= 0) { 264 sock.setSoLinger(linger > 0, linger); 265 } 266 267 } // prepareSocket 268 269 270 } // class DefaultClientConnectionOperator 271