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