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