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