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