Home | History | Annotate | Download | only in ch
      1 /*
      2  * Copyright (c) 2001, 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.net.*;
     30 import java.nio.*;
     31 import java.nio.channels.*;
     32 
     33 
     34 // Make a datagram-socket channel look like a datagram socket.
     35 //
     36 // The methods in this class are defined in exactly the same order as in
     37 // java.net.DatagramSocket so as to simplify tracking future changes to that
     38 // class.
     39 //
     40 
     41 public class DatagramSocketAdaptor
     42     extends DatagramSocket
     43 {
     44 
     45     // The channel being adapted
     46     private final DatagramChannelImpl dc;
     47 
     48     // Timeout "option" value for receives
     49     private volatile int timeout = 0;
     50 
     51     // ## super will create a useless impl
     52     private DatagramSocketAdaptor(DatagramChannelImpl dc) throws IOException {
     53         // Invoke the DatagramSocketAdaptor(SocketAddress) constructor,
     54         // passing a dummy DatagramSocketImpl object to aovid any native
     55         // resource allocation in super class and invoking our bind method
     56         // before the dc field is initialized.
     57         super(dummyDatagramSocket);
     58         this.dc = dc;
     59     }
     60 
     61     public static DatagramSocket create(DatagramChannelImpl dc) {
     62         try {
     63             return new DatagramSocketAdaptor(dc);
     64         } catch (IOException x) {
     65             throw new Error(x);
     66         }
     67     }
     68 
     69     private void connectInternal(SocketAddress remote)
     70         throws SocketException
     71     {
     72         InetSocketAddress isa = Net.asInetSocketAddress(remote);
     73         int port = isa.getPort();
     74         if (port < 0 || port > 0xFFFF)
     75             throw new IllegalArgumentException("connect: " + port);
     76         if (remote == null)
     77             throw new IllegalArgumentException("connect: null address");
     78         if (isClosed())
     79             return;
     80         try {
     81             dc.connect(remote);
     82         } catch (Exception x) {
     83             Net.translateToSocketException(x);
     84         }
     85     }
     86 
     87     public void bind(SocketAddress local) throws SocketException {
     88         try {
     89             if (local == null)
     90                 local = new InetSocketAddress(0);
     91             dc.bind(local);
     92         } catch (Exception x) {
     93             Net.translateToSocketException(x);
     94         }
     95     }
     96 
     97     public void connect(InetAddress address, int port) {
     98         try {
     99             connectInternal(new InetSocketAddress(address, port));
    100         } catch (SocketException x) {
    101             // Yes, j.n.DatagramSocket really does this
    102         }
    103     }
    104 
    105     public void connect(SocketAddress remote) throws SocketException {
    106         if (remote == null)
    107             throw new IllegalArgumentException("Address can't be null");
    108         connectInternal(remote);
    109     }
    110 
    111     public void disconnect() {
    112         try {
    113             dc.disconnect();
    114         } catch (IOException x) {
    115             throw new Error(x);
    116         }
    117     }
    118 
    119     public boolean isBound() {
    120         return dc.localAddress() != null;
    121     }
    122 
    123     public boolean isConnected() {
    124         return dc.remoteAddress() != null;
    125     }
    126 
    127     public InetAddress getInetAddress() {
    128         return (isConnected()
    129                 ? Net.asInetSocketAddress(dc.remoteAddress()).getAddress()
    130                 : null);
    131     }
    132 
    133     public int getPort() {
    134         return (isConnected()
    135                 ? Net.asInetSocketAddress(dc.remoteAddress()).getPort()
    136                 : -1);
    137     }
    138 
    139     public void send(DatagramPacket p) throws IOException {
    140         synchronized (dc.blockingLock()) {
    141             if (!dc.isBlocking())
    142                 throw new IllegalBlockingModeException();
    143             try {
    144                 synchronized (p) {
    145                     ByteBuffer bb = ByteBuffer.wrap(p.getData(),
    146                                                     p.getOffset(),
    147                                                     p.getLength());
    148                     if (dc.isConnected()) {
    149                         if (p.getAddress() == null) {
    150                             // Legacy DatagramSocket will send in this case
    151                             // and set address and port of the packet
    152                             InetSocketAddress isa = (InetSocketAddress)
    153                                                     dc.remoteAddress();
    154                             p.setPort(isa.getPort());
    155                             p.setAddress(isa.getAddress());
    156                             dc.write(bb);
    157                         } else {
    158                             // Target address may not match connected address
    159                             dc.send(bb, p.getSocketAddress());
    160                         }
    161                     } else {
    162                         // Not connected so address must be valid or throw
    163                         dc.send(bb, p.getSocketAddress());
    164                     }
    165                 }
    166             } catch (IOException x) {
    167                 Net.translateException(x);
    168             }
    169         }
    170     }
    171 
    172     // Must hold dc.blockingLock()
    173     //
    174     private SocketAddress receive(ByteBuffer bb) throws IOException {
    175         if (timeout == 0) {
    176             return dc.receive(bb);
    177         }
    178 
    179         dc.configureBlocking(false);
    180         try {
    181             int n;
    182             SocketAddress sender;
    183             if ((sender = dc.receive(bb)) != null)
    184                 return sender;
    185             long to = timeout;
    186             for (;;) {
    187                 if (!dc.isOpen())
    188                      throw new ClosedChannelException();
    189                 long st = System.currentTimeMillis();
    190                 int result = dc.poll(Net.POLLIN, to);
    191                 if (result > 0 &&
    192                         ((result & Net.POLLIN) != 0)) {
    193                     if ((sender = dc.receive(bb)) != null)
    194                         return sender;
    195                 }
    196                 to -= System.currentTimeMillis() - st;
    197                 if (to <= 0)
    198                     throw new SocketTimeoutException();
    199 
    200             }
    201         } finally {
    202             if (dc.isOpen())
    203                 dc.configureBlocking(true);
    204         }
    205     }
    206 
    207     public void receive(DatagramPacket p) throws IOException {
    208         synchronized (dc.blockingLock()) {
    209             if (!dc.isBlocking())
    210                 throw new IllegalBlockingModeException();
    211             try {
    212                 synchronized (p) {
    213                     ByteBuffer bb = ByteBuffer.wrap(p.getData(),
    214                                                     p.getOffset(),
    215                                                     p.getLength());
    216                     SocketAddress sender = receive(bb);
    217                     p.setSocketAddress(sender);
    218                     p.setLength(bb.position() - p.getOffset());
    219                 }
    220             } catch (IOException x) {
    221                 Net.translateException(x);
    222             }
    223         }
    224     }
    225 
    226     public InetAddress getLocalAddress() {
    227         if (isClosed())
    228             return null;
    229         SocketAddress local = dc.localAddress();
    230         if (local == null)
    231             local = new InetSocketAddress(0);
    232         InetAddress result = ((InetSocketAddress)local).getAddress();
    233         SecurityManager sm = System.getSecurityManager();
    234         if (sm != null) {
    235             try {
    236                 sm.checkConnect(result.getHostAddress(), -1);
    237             } catch (SecurityException x) {
    238                 return new InetSocketAddress(0).getAddress();
    239             }
    240         }
    241         return result;
    242     }
    243 
    244     public int getLocalPort() {
    245         if (isClosed())
    246             return -1;
    247         try {
    248             SocketAddress local = dc.getLocalAddress();
    249             if (local != null) {
    250                 return ((InetSocketAddress)local).getPort();
    251             }
    252         } catch (Exception x) {
    253         }
    254         return 0;
    255     }
    256 
    257     public void setSoTimeout(int timeout) throws SocketException {
    258         this.timeout = timeout;
    259     }
    260 
    261     public int getSoTimeout() throws SocketException {
    262         return timeout;
    263     }
    264 
    265     private void setBooleanOption(SocketOption<Boolean> name, boolean value)
    266         throws SocketException
    267     {
    268         try {
    269             dc.setOption(name, value);
    270         } catch (IOException x) {
    271             Net.translateToSocketException(x);
    272         }
    273     }
    274 
    275     private void setIntOption(SocketOption<Integer> name, int value)
    276         throws SocketException
    277     {
    278         try {
    279             dc.setOption(name, value);
    280         } catch (IOException x) {
    281             Net.translateToSocketException(x);
    282         }
    283     }
    284 
    285     private boolean getBooleanOption(SocketOption<Boolean> name) throws SocketException {
    286         try {
    287             return dc.getOption(name).booleanValue();
    288         } catch (IOException x) {
    289             Net.translateToSocketException(x);
    290             return false;       // keep compiler happy
    291         }
    292     }
    293 
    294     private int getIntOption(SocketOption<Integer> name) throws SocketException {
    295         try {
    296             return dc.getOption(name).intValue();
    297         } catch (IOException x) {
    298             Net.translateToSocketException(x);
    299             return -1;          // keep compiler happy
    300         }
    301     }
    302 
    303     public void setSendBufferSize(int size) throws SocketException {
    304         if (size <= 0)
    305             throw new IllegalArgumentException("Invalid send size");
    306         setIntOption(StandardSocketOptions.SO_SNDBUF, size);
    307     }
    308 
    309     public int getSendBufferSize() throws SocketException {
    310         return getIntOption(StandardSocketOptions.SO_SNDBUF);
    311     }
    312 
    313     public void setReceiveBufferSize(int size) throws SocketException {
    314         if (size <= 0)
    315             throw new IllegalArgumentException("Invalid receive size");
    316         setIntOption(StandardSocketOptions.SO_RCVBUF, size);
    317     }
    318 
    319     public int getReceiveBufferSize() throws SocketException {
    320         return getIntOption(StandardSocketOptions.SO_RCVBUF);
    321     }
    322 
    323     public void setReuseAddress(boolean on) throws SocketException {
    324         setBooleanOption(StandardSocketOptions.SO_REUSEADDR, on);
    325     }
    326 
    327     public boolean getReuseAddress() throws SocketException {
    328         return getBooleanOption(StandardSocketOptions.SO_REUSEADDR);
    329 
    330     }
    331 
    332     public void setBroadcast(boolean on) throws SocketException {
    333         setBooleanOption(StandardSocketOptions.SO_BROADCAST, on);
    334     }
    335 
    336     public boolean getBroadcast() throws SocketException {
    337         return getBooleanOption(StandardSocketOptions.SO_BROADCAST);
    338     }
    339 
    340     public void setTrafficClass(int tc) throws SocketException {
    341         setIntOption(StandardSocketOptions.IP_TOS, tc);
    342     }
    343 
    344     public int getTrafficClass() throws SocketException {
    345         return getIntOption(StandardSocketOptions.IP_TOS);
    346     }
    347 
    348     public void close() {
    349         try {
    350             dc.close();
    351         } catch (IOException x) {
    352             throw new Error(x);
    353         }
    354     }
    355 
    356     public boolean isClosed() {
    357         return !dc.isOpen();
    358     }
    359 
    360     public DatagramChannel getChannel() {
    361         return dc;
    362     }
    363 
    364     // Android-added: for testing and internal use.
    365     @Override
    366     public final FileDescriptor getFileDescriptor$() {
    367         return dc.fd;
    368     }
    369 
    370    /*
    371     * A dummy implementation of DatagramSocketImpl that can be passed to the
    372     * DatagramSocket constructor so that no native resources are allocated in
    373     * super class.
    374     */
    375    private static final DatagramSocketImpl dummyDatagramSocket
    376        = new DatagramSocketImpl()
    377    {
    378        protected void create() throws SocketException {}
    379 
    380        protected void bind(int lport, InetAddress laddr) throws SocketException {}
    381 
    382        protected void send(DatagramPacket p) throws IOException {}
    383 
    384        protected int peek(InetAddress i) throws IOException { return 0; }
    385 
    386        protected int peekData(DatagramPacket p) throws IOException { return 0; }
    387 
    388        protected void receive(DatagramPacket p) throws IOException {}
    389 
    390        @Deprecated
    391        protected void setTTL(byte ttl) throws IOException {}
    392 
    393        @Deprecated
    394        protected byte getTTL() throws IOException { return 0; }
    395 
    396        protected void setTimeToLive(int ttl) throws IOException {}
    397 
    398        protected int getTimeToLive() throws IOException { return 0;}
    399 
    400        protected void join(InetAddress inetaddr) throws IOException {}
    401 
    402        protected void leave(InetAddress inetaddr) throws IOException {}
    403 
    404        protected void joinGroup(SocketAddress mcastaddr,
    405                                  NetworkInterface netIf) throws IOException {}
    406 
    407        protected void leaveGroup(SocketAddress mcastaddr,
    408                                  NetworkInterface netIf) throws IOException {}
    409 
    410        protected void close() {}
    411 
    412        public Object getOption(int optID) throws SocketException { return null;}
    413 
    414        public void setOption(int optID, Object value) throws SocketException {}
    415    };
    416 }
    417