1 /* 2 * Copyright (c) 2000, 2006, 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 38 // Make a socket channel look like a socket. 39 // 40 // The only aspects of java.net.Socket-hood that we don't attempt to emulate 41 // here are the interrupted-I/O exceptions (which our Solaris implementations 42 // attempt to support) and the sending of urgent data. Otherwise an adapted 43 // socket should look enough like a real java.net.Socket to fool most of the 44 // developers most of the time, right down to the exception message strings. 45 // 46 // The methods in this class are defined in exactly the same order as in 47 // java.net.Socket so as to simplify tracking future changes to that class. 48 // 49 50 public class SocketAdaptor 51 extends Socket 52 { 53 54 // The channel being adapted 55 private final SocketChannelImpl sc; 56 57 // Option adaptor object, created on demand 58 private volatile OptionAdaptor opts = null; 59 60 // Timeout "option" value for reads 61 private volatile int timeout = 0; 62 63 // Traffic-class/Type-of-service 64 private volatile int trafficClass = 0; 65 66 67 // ## super will create a useless impl 68 private SocketAdaptor(SocketChannelImpl sc) { 69 this.sc = sc; 70 } 71 72 public static Socket create(SocketChannelImpl sc) { 73 return new SocketAdaptor(sc); 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 sc.connect(remote); 100 return; 101 } 102 103 // Implement timeout with a selector 104 SelectionKey sk = null; 105 Selector sel = null; 106 sc.configureBlocking(false); 107 try { 108 if (sc.connect(remote)) 109 return; 110 sel = Util.getTemporarySelector(sc); 111 sk = sc.register(sel, SelectionKey.OP_CONNECT); 112 long to = timeout; 113 for (;;) { 114 if (!sc.isOpen()) 115 throw new ClosedChannelException(); 116 long st = System.currentTimeMillis(); 117 int ns = sel.select(to); 118 if (ns > 0 && 119 sk.isConnectable() && sc.finishConnect()) 120 break; 121 sel.selectedKeys().remove(sk); 122 to -= System.currentTimeMillis() - st; 123 if (to <= 0) { 124 try { 125 sc.close(); 126 } catch (IOException x) { } 127 throw new SocketTimeoutException(); 128 } 129 } 130 } finally { 131 if (sk != null) 132 sk.cancel(); 133 if (sc.isOpen()) 134 sc.configureBlocking(true); 135 if (sel != null) 136 Util.releaseTemporarySelector(sel); 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 if (local == null) 149 local = new InetSocketAddress(0); 150 sc.bind(local); 151 } catch (Exception x) { 152 Net.translateException(x); 153 } 154 } 155 156 public InetAddress getInetAddress() { 157 if (!sc.isConnected()) 158 return null; 159 return Net.asInetSocketAddress(sc.remoteAddress()).getAddress(); 160 } 161 162 public InetAddress getLocalAddress() { 163 if (!sc.isBound()) 164 return new InetSocketAddress(0).getAddress(); 165 return Net.getRevealedLocalAddress(sc.localAddress()).getAddress(); 166 } 167 168 public int getPort() { 169 if (!sc.isConnected()) 170 return 0; 171 return Net.asInetSocketAddress(sc.remoteAddress()).getPort(); 172 } 173 174 public int getLocalPort() { 175 if (!sc.isBound()) 176 return -1; 177 return Net.asInetSocketAddress(sc.localAddress()).getPort(); 178 } 179 180 private class SocketInputStream 181 extends ChannelInputStream 182 { 183 private SocketInputStream() { 184 super(sc); 185 } 186 187 protected int read(ByteBuffer bb) 188 throws IOException 189 { 190 synchronized (sc.blockingLock()) { 191 if (!sc.isBlocking()) 192 throw new IllegalBlockingModeException(); 193 if (timeout == 0) 194 return sc.read(bb); 195 196 // Implement timeout with a selector 197 SelectionKey sk = null; 198 Selector sel = null; 199 sc.configureBlocking(false); 200 try { 201 int n; 202 if ((n = sc.read(bb)) != 0) 203 return n; 204 sel = Util.getTemporarySelector(sc); 205 sk = sc.register(sel, SelectionKey.OP_READ); 206 long to = timeout; 207 for (;;) { 208 if (!sc.isOpen()) 209 throw new ClosedChannelException(); 210 long st = System.currentTimeMillis(); 211 int ns = sel.select(to); 212 if (ns > 0 && sk.isReadable()) { 213 if ((n = sc.read(bb)) != 0) 214 return n; 215 } 216 sel.selectedKeys().remove(sk); 217 to -= System.currentTimeMillis() - st; 218 if (to <= 0) 219 throw new SocketTimeoutException(); 220 } 221 } finally { 222 if (sk != null) 223 sk.cancel(); 224 if (sc.isOpen()) 225 sc.configureBlocking(true); 226 if (sel != null) 227 Util.releaseTemporarySelector(sel); 228 } 229 230 } 231 } 232 } 233 234 private InputStream socketInputStream = null; 235 236 public InputStream getInputStream() throws IOException { 237 if (!sc.isOpen()) 238 throw new SocketException("Socket is closed"); 239 if (!sc.isConnected()) 240 throw new SocketException("Socket is not connected"); 241 if (!sc.isInputOpen()) 242 throw new SocketException("Socket input is shutdown"); 243 if (socketInputStream == null) { 244 try { 245 socketInputStream = AccessController.doPrivileged( 246 new PrivilegedExceptionAction<InputStream>() { 247 public InputStream run() throws IOException { 248 return new SocketInputStream(); 249 } 250 }); 251 } catch (java.security.PrivilegedActionException e) { 252 throw (IOException)e.getException(); 253 } 254 } 255 return socketInputStream; 256 } 257 258 public OutputStream getOutputStream() throws IOException { 259 if (!sc.isOpen()) 260 throw new SocketException("Socket is closed"); 261 if (!sc.isConnected()) 262 throw new SocketException("Socket is not connected"); 263 if (!sc.isOutputOpen()) 264 throw new SocketException("Socket output is shutdown"); 265 OutputStream os = null; 266 try { 267 os = AccessController.doPrivileged( 268 new PrivilegedExceptionAction<OutputStream>() { 269 public OutputStream run() throws IOException { 270 return Channels.newOutputStream(sc); 271 } 272 }); 273 } catch (java.security.PrivilegedActionException e) { 274 throw (IOException)e.getException(); 275 } 276 return os; 277 } 278 279 private OptionAdaptor opts() { 280 if (opts == null) 281 opts = new OptionAdaptor(sc); 282 return opts; 283 } 284 285 public void setTcpNoDelay(boolean on) throws SocketException { 286 opts().setTcpNoDelay(on); 287 } 288 289 public boolean getTcpNoDelay() throws SocketException { 290 return opts().getTcpNoDelay(); 291 } 292 293 public void setSoLinger(boolean on, int linger) throws SocketException { 294 opts().setSoLinger(on, linger); 295 } 296 297 public int getSoLinger() throws SocketException { 298 return opts().getSoLinger(); 299 } 300 301 public void sendUrgentData(int data) throws IOException { 302 throw new SocketException("Urgent data not supported"); 303 } 304 305 public void setOOBInline(boolean on) throws SocketException { 306 opts().setOOBInline(on); 307 } 308 309 public boolean getOOBInline() throws SocketException { 310 return opts().getOOBInline(); 311 } 312 313 public void setSoTimeout(int timeout) throws SocketException { 314 if (timeout < 0) 315 throw new IllegalArgumentException("timeout can't be negative"); 316 this.timeout = timeout; 317 } 318 319 public int getSoTimeout() throws SocketException { 320 return timeout; 321 } 322 323 public void setSendBufferSize(int size) throws SocketException { 324 opts().setSendBufferSize(size); 325 } 326 327 public int getSendBufferSize() throws SocketException { 328 return opts().getSendBufferSize(); 329 } 330 331 public void setReceiveBufferSize(int size) throws SocketException { 332 opts().setReceiveBufferSize(size); 333 } 334 335 public int getReceiveBufferSize() throws SocketException { 336 return opts().getReceiveBufferSize(); 337 } 338 339 public void setKeepAlive(boolean on) throws SocketException { 340 opts().setKeepAlive(on); 341 } 342 343 public boolean getKeepAlive() throws SocketException { 344 return opts().getKeepAlive(); 345 } 346 347 public void setTrafficClass(int tc) throws SocketException { 348 opts().setTrafficClass(tc); 349 trafficClass = tc; 350 } 351 352 public int getTrafficClass() throws SocketException { 353 int tc = opts().getTrafficClass(); 354 if (tc < 0) { 355 tc = trafficClass; 356 } 357 return tc; 358 } 359 360 public void setReuseAddress(boolean on) throws SocketException { 361 opts().setReuseAddress(on); 362 } 363 364 public boolean getReuseAddress() throws SocketException { 365 return opts().getReuseAddress(); 366 } 367 368 public void close() throws IOException { 369 try { 370 sc.close(); 371 } catch (Exception x) { 372 Net.translateToSocketException(x); 373 } 374 } 375 376 public void shutdownInput() throws IOException { 377 try { 378 sc.shutdownInput(); 379 } catch (Exception x) { 380 Net.translateException(x); 381 } 382 } 383 384 public void shutdownOutput() throws IOException { 385 try { 386 sc.shutdownOutput(); 387 } catch (Exception x) { 388 Net.translateException(x); 389 } 390 } 391 392 public String toString() { 393 if (sc.isConnected()) 394 return "Socket[addr=" + getInetAddress() + 395 ",port=" + getPort() + 396 ",localport=" + getLocalPort() + "]"; 397 return "Socket[unconnected]"; 398 } 399 400 public boolean isConnected() { 401 return sc.isConnected(); 402 } 403 404 public boolean isBound() { 405 return sc.isBound(); 406 } 407 408 public boolean isClosed() { 409 return !sc.isOpen(); 410 } 411 412 public boolean isInputShutdown() { 413 return !sc.isInputOpen(); 414 } 415 416 public boolean isOutputShutdown() { 417 return !sc.isOutputOpen(); 418 } 419 420 }