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 
  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     // Timeout "option" value for reads
  58     private volatile int timeout = 0;
  59 
  60     private SocketAdaptor(SocketChannelImpl sc) throws SocketException {
  61         super((SocketImpl) null);
  62         this.sc = sc;
  63     }
  64 
  65     public static Socket create(SocketChannelImpl sc) {
  66         try {
  67             return new SocketAdaptor(sc);
  68         } catch (SocketException e) {
  69             throw new InternalError("Should not reach here");
  70         }
  71     }
  72 
  73     public SocketChannel getChannel() {
  74         return sc;
  75     }
  76 
  77     // Override this method just to protect against changes in the superclass
  78     //
  79     public void connect(SocketAddress remote) throws IOException {
  80         connect(remote, 0);
  81     }
  82 
  83     public void connect(SocketAddress remote, int timeout) throws IOException {
  84         if (remote == null)
  85             throw new IllegalArgumentException("connect: The address can't be null");
  86         if (timeout < 0)
  87             throw new IllegalArgumentException("connect: timeout can't be negative");
  88 
  89         synchronized (sc.blockingLock()) {
  90             if (!sc.isBlocking())
  91                 throw new IllegalBlockingModeException();
  92 
  93             try {
  94 
  95                 if (timeout == 0) {
  96                     sc.connect(remote);
  97                     return;
  98                 }
  99 
 100                 sc.configureBlocking(false);
 101                 try {
 102                     if (sc.connect(remote))
 103                         return;
 104                     long to = timeout;
 105                     for (;;) {
 106                         if (!sc.isOpen())
 107                             throw new ClosedChannelException();
 108                         long st = System.currentTimeMillis();
 109 
 110                         int result = sc.poll(PollArrayWrapper.POLLCONN, to);
 111                         if (result > 0 && sc.finishConnect())
 112                             break;
 113                         to -= System.currentTimeMillis() - st;
 114                         if (to <= 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             SocketAddress local = sc.localAddress();
 153             if (local != null)
 154                 return ((InetSocketAddress)local).getAddress();
 155         }
 156         return new InetSocketAddress(0).getAddress();
 157     }
 158 
 159     public int getPort() {
 160         SocketAddress remote = sc.remoteAddress();
 161         if (remote == null) {
 162             return 0;
 163         } else {
 164             return ((InetSocketAddress)remote).getPort();
 165         }
 166     }
 167 
 168     public int getLocalPort() {
 169         SocketAddress local = sc.localAddress();
 170         if (local == null) {
 171             return -1;
 172         } else {
 173             return ((InetSocketAddress)local).getPort();
 174         }
 175     }
 176 
 177     private class SocketInputStream
 178         extends ChannelInputStream
 179     {
 180         private SocketInputStream() {
 181             super(sc);
 182         }
 183 
 184         protected int read(ByteBuffer bb)
 185             throws IOException
 186         {
 187             synchronized (sc.blockingLock()) {
 188                 if (!sc.isBlocking())
 189                     throw new IllegalBlockingModeException();
 190                 if (timeout == 0)
 191                     return sc.read(bb);
 192                 sc.configureBlocking(false);
 193 
 194                 try {
 195                     int n;
 196                     if ((n = sc.read(bb)) != 0)
 197                         return n;
 198                     long to = timeout;
 199                     for (;;) {
 200                         if (!sc.isOpen())
 201                             throw new ClosedChannelException();
 202                         long st = System.currentTimeMillis();
 203                         int result = sc.poll(PollArrayWrapper.POLLIN, to);
 204                         if (result > 0) {
 205                             if ((n = sc.read(bb)) != 0)
 206                                 return n;
 207                         }
 208                         to -= System.currentTimeMillis() - st;
 209                         if (to <= 0)
 210                             throw new SocketTimeoutException();
 211                     }
 212                 } finally {
 213                     if (sc.isOpen())
 214                         sc.configureBlocking(true);
 215                 }
 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         synchronized (sc.blockingLock()) {
 324             if (!sc.isBlocking())
 325                 throw new IllegalBlockingModeException();
 326             int n = sc.sendOutOfBandData((byte)data);
 327             assert n == 1;
 328         }
 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 }