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