• 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/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