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 */ DefaultClientConnectionOperator(SchemeRegistry schemes)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 createConnection()94 public OperatedClientConnection createConnection() { 95 return new DefaultClientConnection(); 96 } 97 98 99 // non-javadoc, see interface ClientConnectionOperator openConnection(OperatedClientConnection conn, HttpHost target, InetAddress local, HttpContext context, HttpParams params)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 updateSecureConnection(OperatedClientConnection conn, HttpHost target, HttpContext context, HttpParams params)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 */ prepareSocket(Socket sock, HttpContext context, HttpParams params)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