1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. Oracle designates this 9 * particular file as subject to the "Classpath" exception as provided 10 * by Oracle in the LICENSE file that accompanied this code. 11 * 12 * This code is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 * version 2 for more details (a copy is included in the LICENSE file that 16 * accompanied this code). 17 * 18 * You should have received a copy of the GNU General Public License version 19 * 2 along with this work; if not, write to the Free Software Foundation, 20 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21 * 22 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 23 * or visit www.oracle.com if you need additional information or have any 24 * questions. 25 */ 26 27 package sun.nio.ch; 28 29 import java.io.*; 30 import java.net.*; 31 import java.nio.*; 32 import java.nio.channels.*; 33 import java.security.AccessController; 34 import java.security.PrivilegedExceptionAction; 35 36 37 // Make a socket channel look like a socket. 38 // 39 // The only aspects of java.net.Socket-hood that we don't attempt to emulate 40 // here are the interrupted-I/O exceptions (which our Solaris implementations 41 // attempt to support) and the sending of urgent data. Otherwise an adapted 42 // socket should look enough like a real java.net.Socket to fool most of the 43 // developers most of the time, right down to the exception message strings. 44 // 45 // The methods in this class are defined in exactly the same order as in 46 // java.net.Socket so as to simplify tracking future changes to that class. 47 // 48 49 public class SocketAdaptor 50 extends Socket 51 { 52 53 // The channel being adapted 54 private final SocketChannelImpl sc; 55 56 // Timeout "option" value for reads 57 private volatile int timeout = 0; 58 SocketAdaptor(SocketChannelImpl sc)59 private SocketAdaptor(SocketChannelImpl sc) throws SocketException { 60 super(new FileDescriptorHolderSocketImpl(sc.getFD())); 61 this.sc = sc; 62 } 63 create(SocketChannelImpl sc)64 public static Socket create(SocketChannelImpl sc) { 65 try { 66 return new SocketAdaptor(sc); 67 } catch (SocketException e) { 68 throw new InternalError("Should not reach here"); 69 } 70 } 71 getChannel()72 public SocketChannel getChannel() { 73 return sc; 74 } 75 76 // Override this method just to protect against changes in the superclass 77 // connect(SocketAddress remote)78 public void connect(SocketAddress remote) throws IOException { 79 connect(remote, 0); 80 } 81 connect(SocketAddress remote, int timeout)82 public void connect(SocketAddress remote, int timeout) throws IOException { 83 if (remote == null) 84 throw new IllegalArgumentException("connect: The address can't be null"); 85 if (timeout < 0) 86 throw new IllegalArgumentException("connect: timeout can't be negative"); 87 88 synchronized (sc.blockingLock()) { 89 if (!sc.isBlocking()) 90 throw new IllegalBlockingModeException(); 91 92 try { 93 94 if (timeout == 0) { 95 // Android-changed: Be consistent 96 try { 97 sc.connect(remote); 98 } catch (Exception ex) { 99 Net.translateException(ex); 100 } 101 102 return; 103 } 104 105 sc.configureBlocking(false); 106 try { 107 if (sc.connect(remote)) 108 return; 109 long to = timeout; 110 for (;;) { 111 if (!sc.isOpen()) 112 throw new ClosedChannelException(); 113 long st = System.currentTimeMillis(); 114 115 int result = sc.poll(Net.POLLCONN, to); 116 if (result > 0 && sc.finishConnect()) 117 break; 118 to -= System.currentTimeMillis() - st; 119 if (to <= 0) { 120 try { 121 sc.close(); 122 } catch (IOException x) { } 123 throw new SocketTimeoutException(); 124 } 125 } 126 } finally { 127 if (sc.isOpen()) 128 sc.configureBlocking(true); 129 } 130 131 } catch (Exception x) { 132 Net.translateException(x, true); 133 } 134 } 135 136 } 137 bind(SocketAddress local)138 public void bind(SocketAddress local) throws IOException { 139 try { 140 sc.bind(local); 141 } catch (Exception x) { 142 Net.translateException(x); 143 } 144 } 145 getInetAddress()146 public InetAddress getInetAddress() { 147 // Use #remoteAddress and do manual isConnected check. #getRemoteAddress() returns 148 // non-null result before connection. 149 if (!isConnected()) { 150 return null; 151 } 152 SocketAddress remote = sc.remoteAddress(); 153 if (remote == null) { 154 return null; 155 } else { 156 return ((InetSocketAddress)remote).getAddress(); 157 } 158 } 159 getLocalAddress()160 public InetAddress getLocalAddress() { 161 if (sc.isOpen()) { 162 InetSocketAddress local = sc.localAddress(); 163 if (local != null) { 164 return Net.getRevealedLocalAddress(local).getAddress(); 165 } 166 } 167 return new InetSocketAddress(0).getAddress(); 168 } 169 getPort()170 public int getPort() { 171 // Use #remoteAddress and do manual isConnected check. #getRemoteAddress() returns 172 // non-null result before connection. 173 if (!isConnected()) { 174 return 0; 175 } 176 SocketAddress remote = sc.remoteAddress(); 177 if (remote == null) { 178 return 0; 179 } else { 180 return ((InetSocketAddress)remote).getPort(); 181 } 182 } 183 getLocalPort()184 public int getLocalPort() { 185 SocketAddress local = sc.localAddress(); 186 if (local == null) { 187 return -1; 188 } else { 189 return ((InetSocketAddress)local).getPort(); 190 } 191 } 192 193 private class SocketInputStream 194 extends ChannelInputStream 195 { SocketInputStream()196 private SocketInputStream() { 197 super(sc); 198 } 199 read(ByteBuffer bb)200 protected int read(ByteBuffer bb) 201 throws IOException 202 { 203 synchronized (sc.blockingLock()) { 204 if (!sc.isBlocking()) 205 throw new IllegalBlockingModeException(); 206 if (timeout == 0) 207 return sc.read(bb); 208 sc.configureBlocking(false); 209 210 try { 211 int n; 212 if ((n = sc.read(bb)) != 0) 213 return n; 214 long to = timeout; 215 for (;;) { 216 if (!sc.isOpen()) 217 throw new ClosedChannelException(); 218 long st = System.currentTimeMillis(); 219 int result = sc.poll(Net.POLLIN, to); 220 if (result > 0) { 221 if ((n = sc.read(bb)) != 0) 222 return n; 223 } 224 to -= System.currentTimeMillis() - st; 225 if (to <= 0) 226 throw new SocketTimeoutException(); 227 } 228 } finally { 229 if (sc.isOpen()) 230 sc.configureBlocking(true); 231 } 232 233 } 234 } 235 } 236 237 private InputStream socketInputStream = null; 238 getInputStream()239 public InputStream getInputStream() throws IOException { 240 if (!sc.isOpen()) 241 throw new SocketException("Socket is closed"); 242 if (!sc.isConnected()) 243 throw new SocketException("Socket is not connected"); 244 if (!sc.isInputOpen()) 245 throw new SocketException("Socket input is shutdown"); 246 if (socketInputStream == null) { 247 try { 248 socketInputStream = AccessController.doPrivileged( 249 new PrivilegedExceptionAction<InputStream>() { 250 public InputStream run() throws IOException { 251 return new SocketInputStream(); 252 } 253 }); 254 } catch (java.security.PrivilegedActionException e) { 255 throw (IOException)e.getException(); 256 } 257 } 258 return socketInputStream; 259 } 260 getOutputStream()261 public OutputStream getOutputStream() throws IOException { 262 if (!sc.isOpen()) 263 throw new SocketException("Socket is closed"); 264 if (!sc.isConnected()) 265 throw new SocketException("Socket is not connected"); 266 if (!sc.isOutputOpen()) 267 throw new SocketException("Socket output is shutdown"); 268 OutputStream os = null; 269 try { 270 os = AccessController.doPrivileged( 271 new PrivilegedExceptionAction<OutputStream>() { 272 public OutputStream run() throws IOException { 273 return Channels.newOutputStream(sc); 274 } 275 }); 276 } catch (java.security.PrivilegedActionException e) { 277 throw (IOException)e.getException(); 278 } 279 return os; 280 } 281 setBooleanOption(SocketOption<Boolean> name, boolean value)282 private void setBooleanOption(SocketOption<Boolean> name, boolean value) 283 throws SocketException 284 { 285 try { 286 sc.setOption(name, value); 287 } catch (IOException x) { 288 Net.translateToSocketException(x); 289 } 290 } 291 setIntOption(SocketOption<Integer> name, int value)292 private void setIntOption(SocketOption<Integer> name, int value) 293 throws SocketException 294 { 295 try { 296 sc.setOption(name, value); 297 } catch (IOException x) { 298 Net.translateToSocketException(x); 299 } 300 } 301 getBooleanOption(SocketOption<Boolean> name)302 private boolean getBooleanOption(SocketOption<Boolean> name) throws SocketException { 303 try { 304 return sc.getOption(name).booleanValue(); 305 } catch (IOException x) { 306 Net.translateToSocketException(x); 307 return false; // keep compiler happy 308 } 309 } 310 getIntOption(SocketOption<Integer> name)311 private int getIntOption(SocketOption<Integer> name) throws SocketException { 312 try { 313 return sc.getOption(name).intValue(); 314 } catch (IOException x) { 315 Net.translateToSocketException(x); 316 return -1; // keep compiler happy 317 } 318 } 319 setTcpNoDelay(boolean on)320 public void setTcpNoDelay(boolean on) throws SocketException { 321 setBooleanOption(StandardSocketOptions.TCP_NODELAY, on); 322 } 323 getTcpNoDelay()324 public boolean getTcpNoDelay() throws SocketException { 325 return getBooleanOption(StandardSocketOptions.TCP_NODELAY); 326 } 327 setSoLinger(boolean on, int linger)328 public void setSoLinger(boolean on, int linger) throws SocketException { 329 if (!on) 330 linger = -1; 331 setIntOption(StandardSocketOptions.SO_LINGER, linger); 332 } 333 getSoLinger()334 public int getSoLinger() throws SocketException { 335 return getIntOption(StandardSocketOptions.SO_LINGER); 336 } 337 sendUrgentData(int data)338 public void sendUrgentData(int data) throws IOException { 339 int n = sc.sendOutOfBandData((byte) data); 340 if (n == 0) 341 throw new IOException("Socket buffer full"); 342 } 343 setOOBInline(boolean on)344 public void setOOBInline(boolean on) throws SocketException { 345 setBooleanOption(ExtendedSocketOption.SO_OOBINLINE, on); 346 } 347 getOOBInline()348 public boolean getOOBInline() throws SocketException { 349 return getBooleanOption(ExtendedSocketOption.SO_OOBINLINE); 350 } 351 setSoTimeout(int timeout)352 public void setSoTimeout(int timeout) throws SocketException { 353 if (timeout < 0) 354 throw new IllegalArgumentException("timeout can't be negative"); 355 this.timeout = timeout; 356 } 357 getSoTimeout()358 public int getSoTimeout() throws SocketException { 359 return timeout; 360 } 361 setSendBufferSize(int size)362 public void setSendBufferSize(int size) throws SocketException { 363 // size 0 valid for SocketChannel, invalid for Socket 364 if (size <= 0) 365 throw new IllegalArgumentException("Invalid send size"); 366 setIntOption(StandardSocketOptions.SO_SNDBUF, size); 367 } 368 getSendBufferSize()369 public int getSendBufferSize() throws SocketException { 370 return getIntOption(StandardSocketOptions.SO_SNDBUF); 371 } 372 setReceiveBufferSize(int size)373 public void setReceiveBufferSize(int size) throws SocketException { 374 // size 0 valid for SocketChannel, invalid for Socket 375 if (size <= 0) 376 throw new IllegalArgumentException("Invalid receive size"); 377 setIntOption(StandardSocketOptions.SO_RCVBUF, size); 378 } 379 getReceiveBufferSize()380 public int getReceiveBufferSize() throws SocketException { 381 return getIntOption(StandardSocketOptions.SO_RCVBUF); 382 } 383 setKeepAlive(boolean on)384 public void setKeepAlive(boolean on) throws SocketException { 385 setBooleanOption(StandardSocketOptions.SO_KEEPALIVE, on); 386 } 387 getKeepAlive()388 public boolean getKeepAlive() throws SocketException { 389 return getBooleanOption(StandardSocketOptions.SO_KEEPALIVE); 390 } 391 setTrafficClass(int tc)392 public void setTrafficClass(int tc) throws SocketException { 393 setIntOption(StandardSocketOptions.IP_TOS, tc); 394 } 395 getTrafficClass()396 public int getTrafficClass() throws SocketException { 397 return getIntOption(StandardSocketOptions.IP_TOS); 398 } 399 setReuseAddress(boolean on)400 public void setReuseAddress(boolean on) throws SocketException { 401 setBooleanOption(StandardSocketOptions.SO_REUSEADDR, on); 402 } 403 getReuseAddress()404 public boolean getReuseAddress() throws SocketException { 405 return getBooleanOption(StandardSocketOptions.SO_REUSEADDR); 406 } 407 close()408 public void close() throws IOException { 409 sc.close(); 410 } 411 shutdownInput()412 public void shutdownInput() throws IOException { 413 try { 414 sc.shutdownInput(); 415 } catch (Exception x) { 416 Net.translateException(x); 417 } 418 } 419 shutdownOutput()420 public void shutdownOutput() throws IOException { 421 try { 422 sc.shutdownOutput(); 423 } catch (Exception x) { 424 Net.translateException(x); 425 } 426 } 427 toString()428 public String toString() { 429 if (sc.isConnected()) 430 return "Socket[addr=" + getInetAddress() + 431 ",port=" + getPort() + 432 ",localport=" + getLocalPort() + "]"; 433 return "Socket[unconnected]"; 434 } 435 isConnected()436 public boolean isConnected() { 437 return sc.isConnected(); 438 } 439 isBound()440 public boolean isBound() { 441 return sc.localAddress() != null; 442 } 443 isClosed()444 public boolean isClosed() { 445 return !sc.isOpen(); 446 } 447 isInputShutdown()448 public boolean isInputShutdown() { 449 return !sc.isInputOpen(); 450 } 451 isOutputShutdown()452 public boolean isOutputShutdown() { 453 return !sc.isOutputOpen(); 454 } 455 456 /* 457 * Android-added: for testing and internal use. 458 */ 459 @Override getFileDescriptor$()460 public FileDescriptor getFileDescriptor$() { 461 return sc.getFD(); 462 } 463 } 464