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