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