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 }