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