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