1 /*
2  * ====================================================================
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  * ====================================================================
20  *
21  * This software consists of voluntary contributions made by many
22  * individuals on behalf of the Apache Software Foundation.  For more
23  * information on the Apache Software Foundation, please see
24  * <http://www.apache.org/>.
25  *
26  */
27 
28 package ch.boye.httpclientandroidlib.impl;
29 
30 import java.io.IOException;
31 import java.net.InetAddress;
32 import java.net.InetSocketAddress;
33 import java.net.Socket;
34 import java.net.SocketAddress;
35 import java.net.SocketException;
36 
37 import ch.boye.httpclientandroidlib.HttpInetConnection;
38 import ch.boye.httpclientandroidlib.annotation.NotThreadSafe;
39 import ch.boye.httpclientandroidlib.impl.io.SocketInputBuffer;
40 import ch.boye.httpclientandroidlib.impl.io.SocketOutputBuffer;
41 import ch.boye.httpclientandroidlib.io.SessionInputBuffer;
42 import ch.boye.httpclientandroidlib.io.SessionOutputBuffer;
43 import ch.boye.httpclientandroidlib.params.CoreConnectionPNames;
44 import ch.boye.httpclientandroidlib.params.HttpParams;
45 import ch.boye.httpclientandroidlib.util.Args;
46 import ch.boye.httpclientandroidlib.util.Asserts;
47 
48 /**
49  * Implementation of a client-side HTTP connection that can be bound to an
50  * arbitrary {@link Socket} for receiving data from and transmitting data to
51  * a remote server.
52  *
53  * @since 4.0
54  *
55  * @deprecated (4.3) use {@link DefaultBHttpClientConnection}
56  */
57 @NotThreadSafe
58 @Deprecated
59 public class SocketHttpClientConnection
60         extends AbstractHttpClientConnection implements HttpInetConnection {
61 
62     private volatile boolean open;
63     private volatile Socket socket = null;
64 
SocketHttpClientConnection()65     public SocketHttpClientConnection() {
66         super();
67     }
68 
assertNotOpen()69     protected void assertNotOpen() {
70         Asserts.check(!this.open, "Connection is already open");
71     }
72 
73     @Override
assertOpen()74     protected void assertOpen() {
75         Asserts.check(this.open, "Connection is not open");
76     }
77 
78     /**
79      * Creates an instance of {@link SocketInputBuffer} to be used for
80      * receiving data from the given {@link Socket}.
81      * <p>
82      * This method can be overridden in a super class in order to provide
83      * a custom implementation of {@link SessionInputBuffer} interface.
84      *
85      * @see SocketInputBuffer#SocketInputBuffer(Socket, int, HttpParams)
86      *
87      * @param socket the socket.
88      * @param buffersize the buffer size.
89      * @param params HTTP parameters.
90      * @return session input buffer.
91      * @throws IOException in case of an I/O error.
92      */
createSessionInputBuffer( final Socket socket, final int buffersize, final HttpParams params)93     protected SessionInputBuffer createSessionInputBuffer(
94             final Socket socket,
95             final int buffersize,
96             final HttpParams params) throws IOException {
97         return new SocketInputBuffer(socket, buffersize, params);
98     }
99 
100     /**
101      * Creates an instance of {@link SessionOutputBuffer} to be used for
102      * sending data to the given {@link Socket}.
103      * <p>
104      * This method can be overridden in a super class in order to provide
105      * a custom implementation of {@link SocketOutputBuffer} interface.
106      *
107      * @see SocketOutputBuffer#SocketOutputBuffer(Socket, int, HttpParams)
108      *
109      * @param socket the socket.
110      * @param buffersize the buffer size.
111      * @param params HTTP parameters.
112      * @return session output buffer.
113      * @throws IOException in case of an I/O error.
114      */
createSessionOutputBuffer( final Socket socket, final int buffersize, final HttpParams params)115     protected SessionOutputBuffer createSessionOutputBuffer(
116             final Socket socket,
117             final int buffersize,
118             final HttpParams params) throws IOException {
119         return new SocketOutputBuffer(socket, buffersize, params);
120     }
121 
122     /**
123      * Binds this connection to the given {@link Socket}. This socket will be
124      * used by the connection to send and receive data.
125      * <p>
126      * This method will invoke {@link #createSessionInputBuffer(Socket, int, HttpParams)}
127      * and {@link #createSessionOutputBuffer(Socket, int, HttpParams)} methods
128      * to create session input / output buffers bound to this socket and then
129      * will invoke {@link #init(SessionInputBuffer, SessionOutputBuffer, HttpParams)}
130      * method to pass references to those buffers to the underlying HTTP message
131      * parser and formatter.
132      * <p>
133      * After this method's execution the connection status will be reported
134      * as open and the {@link #isOpen()} will return <code>true</code>.
135      *
136      * @param socket the socket.
137      * @param params HTTP parameters.
138      * @throws IOException in case of an I/O error.
139      */
bind( final Socket socket, final HttpParams params)140     protected void bind(
141             final Socket socket,
142             final HttpParams params) throws IOException {
143         Args.notNull(socket, "Socket");
144         Args.notNull(params, "HTTP parameters");
145         this.socket = socket;
146 
147         final int buffersize = params.getIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, -1);
148         init(
149                 createSessionInputBuffer(socket, buffersize, params),
150                 createSessionOutputBuffer(socket, buffersize, params),
151                 params);
152 
153         this.open = true;
154     }
155 
isOpen()156     public boolean isOpen() {
157         return this.open;
158     }
159 
getSocket()160     protected Socket getSocket() {
161         return this.socket;
162     }
163 
getLocalAddress()164     public InetAddress getLocalAddress() {
165         if (this.socket != null) {
166             return this.socket.getLocalAddress();
167         } else {
168             return null;
169         }
170     }
171 
getLocalPort()172     public int getLocalPort() {
173         if (this.socket != null) {
174             return this.socket.getLocalPort();
175         } else {
176             return -1;
177         }
178     }
179 
getRemoteAddress()180     public InetAddress getRemoteAddress() {
181         if (this.socket != null) {
182             return this.socket.getInetAddress();
183         } else {
184             return null;
185         }
186     }
187 
getRemotePort()188     public int getRemotePort() {
189         if (this.socket != null) {
190             return this.socket.getPort();
191         } else {
192             return -1;
193         }
194     }
195 
setSocketTimeout(final int timeout)196     public void setSocketTimeout(final int timeout) {
197         assertOpen();
198         if (this.socket != null) {
199             try {
200                 this.socket.setSoTimeout(timeout);
201             } catch (final SocketException ignore) {
202                 // It is not quite clear from the Sun's documentation if there are any
203                 // other legitimate cases for a socket exception to be thrown when setting
204                 // SO_TIMEOUT besides the socket being already closed
205             }
206         }
207     }
208 
getSocketTimeout()209     public int getSocketTimeout() {
210         if (this.socket != null) {
211             try {
212                 return this.socket.getSoTimeout();
213             } catch (final SocketException ignore) {
214                 return -1;
215             }
216         } else {
217             return -1;
218         }
219     }
220 
shutdown()221     public void shutdown() throws IOException {
222         this.open = false;
223         final Socket tmpsocket = this.socket;
224         if (tmpsocket != null) {
225             tmpsocket.close();
226         }
227     }
228 
close()229     public void close() throws IOException {
230         if (!this.open) {
231             return;
232         }
233         this.open = false;
234         final Socket sock = this.socket;
235         try {
236             doFlush();
237             try {
238                 try {
239                     sock.shutdownOutput();
240                 } catch (final IOException ignore) {
241                 }
242                 try {
243                     sock.shutdownInput();
244                 } catch (final IOException ignore) {
245                 }
246             } catch (final UnsupportedOperationException ignore) {
247                 // if one isn't supported, the other one isn't either
248             }
249         } finally {
250             sock.close();
251         }
252     }
253 
formatAddress(final StringBuilder buffer, final SocketAddress socketAddress)254     private static void formatAddress(final StringBuilder buffer, final SocketAddress socketAddress) {
255         if (socketAddress instanceof InetSocketAddress) {
256             final InetSocketAddress addr = ((InetSocketAddress) socketAddress);
257             buffer.append(addr.getAddress() != null ? addr.getAddress().getHostAddress() :
258                 addr.getAddress())
259             .append(':')
260             .append(addr.getPort());
261         } else {
262             buffer.append(socketAddress);
263         }
264     }
265 
266     @Override
toString()267     public String toString() {
268         if (this.socket != null) {
269             final StringBuilder buffer = new StringBuilder();
270             final SocketAddress remoteAddress = this.socket.getRemoteSocketAddress();
271             final SocketAddress localAddress = this.socket.getLocalSocketAddress();
272             if (remoteAddress != null && localAddress != null) {
273                 formatAddress(buffer, localAddress);
274                 buffer.append("<->");
275                 formatAddress(buffer, remoteAddress);
276             }
277             return buffer.toString();
278         } else {
279             return super.toString();
280         }
281     }
282 
283 }
284