jdk/src/share/classes/sun/nio/ch/SocketAdaptor.java
changeset 2 90ce3da70b43
child 51 6fe31bc95bbc
equal deleted inserted replaced
0:fd16c54261b3 2:90ce3da70b43
       
     1 /*
       
     2  * Copyright 2000-2006 Sun Microsystems, Inc.  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.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any 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.asInetSocketAddress(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 = (InputStream)AccessController.doPrivileged(
       
   246                     new PrivilegedExceptionAction() {
       
   247                         public Object 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 = (OutputStream)
       
   268                 AccessController.doPrivileged(new PrivilegedExceptionAction() {
       
   269                     public Object 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 }