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
DatagramSocketAdaptor(DatagramChannelImpl dc)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 
create(DatagramChannelImpl dc)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 
connectInternal(SocketAddress remote)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 
bind(SocketAddress local)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 
connect(InetAddress address, int port)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 
connect(SocketAddress remote)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 
disconnect()111     public void disconnect() {
112         try {
113             dc.disconnect();
114         } catch (IOException x) {
115             throw new Error(x);
116         }
117     }
118 
isBound()119     public boolean isBound() {
120         return dc.localAddress() != null;
121     }
122 
isConnected()123     public boolean isConnected() {
124         return dc.remoteAddress() != null;
125     }
126 
getInetAddress()127     public InetAddress getInetAddress() {
128         return (isConnected()
129                 ? Net.asInetSocketAddress(dc.remoteAddress()).getAddress()
130                 : null);
131     }
132 
getPort()133     public int getPort() {
134         return (isConnected()
135                 ? Net.asInetSocketAddress(dc.remoteAddress()).getPort()
136                 : -1);
137     }
138 
send(DatagramPacket p)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     //
receive(ByteBuffer bb)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 
receive(DatagramPacket p)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 
getLocalAddress()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 
getLocalPort()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 
setSoTimeout(int timeout)257     public void setSoTimeout(int timeout) throws SocketException {
258         this.timeout = timeout;
259     }
260 
getSoTimeout()261     public int getSoTimeout() throws SocketException {
262         return timeout;
263     }
264 
setBooleanOption(SocketOption<Boolean> name, boolean value)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 
setIntOption(SocketOption<Integer> name, int value)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 
getBooleanOption(SocketOption<Boolean> name)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 
getIntOption(SocketOption<Integer> name)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 
setSendBufferSize(int size)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 
getSendBufferSize()309     public int getSendBufferSize() throws SocketException {
310         return getIntOption(StandardSocketOptions.SO_SNDBUF);
311     }
312 
setReceiveBufferSize(int size)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 
getReceiveBufferSize()319     public int getReceiveBufferSize() throws SocketException {
320         return getIntOption(StandardSocketOptions.SO_RCVBUF);
321     }
322 
setReuseAddress(boolean on)323     public void setReuseAddress(boolean on) throws SocketException {
324         setBooleanOption(StandardSocketOptions.SO_REUSEADDR, on);
325     }
326 
getReuseAddress()327     public boolean getReuseAddress() throws SocketException {
328         return getBooleanOption(StandardSocketOptions.SO_REUSEADDR);
329 
330     }
331 
setBroadcast(boolean on)332     public void setBroadcast(boolean on) throws SocketException {
333         setBooleanOption(StandardSocketOptions.SO_BROADCAST, on);
334     }
335 
getBroadcast()336     public boolean getBroadcast() throws SocketException {
337         return getBooleanOption(StandardSocketOptions.SO_BROADCAST);
338     }
339 
setTrafficClass(int tc)340     public void setTrafficClass(int tc) throws SocketException {
341         setIntOption(StandardSocketOptions.IP_TOS, tc);
342     }
343 
getTrafficClass()344     public int getTrafficClass() throws SocketException {
345         return getIntOption(StandardSocketOptions.IP_TOS);
346     }
347 
close()348     public void close() {
349         try {
350             dc.close();
351         } catch (IOException x) {
352             throw new Error(x);
353         }
354     }
355 
isClosed()356     public boolean isClosed() {
357         return !dc.isOpen();
358     }
359 
getChannel()360     public DatagramChannel getChannel() {
361         return dc;
362     }
363 
364     /*
365      * Android-added: for testing and internal use.
366      */
367     @Override
getFileDescriptor$()368     public final FileDescriptor getFileDescriptor$() {
369         return dc.fd;
370     }
371 
372    /*
373     * A dummy implementation of DatagramSocketImpl that can be passed to the
374     * DatagramSocket constructor so that no native resources are allocated in
375     * super class.
376     */
377    private static final DatagramSocketImpl dummyDatagramSocket
378        = new DatagramSocketImpl()
379    {
380        protected void create() throws SocketException {}
381 
382        protected void bind(int lport, InetAddress laddr) throws SocketException {}
383 
384        protected void send(DatagramPacket p) throws IOException {}
385 
386        protected int peek(InetAddress i) throws IOException { return 0; }
387 
388        protected int peekData(DatagramPacket p) throws IOException { return 0; }
389 
390        protected void receive(DatagramPacket p) throws IOException {}
391 
392        @Deprecated
393        protected void setTTL(byte ttl) throws IOException {}
394 
395        @Deprecated
396        protected byte getTTL() throws IOException { return 0; }
397 
398        protected void setTimeToLive(int ttl) throws IOException {}
399 
400        protected int getTimeToLive() throws IOException { return 0;}
401 
402        protected void join(InetAddress inetaddr) throws IOException {}
403 
404        protected void leave(InetAddress inetaddr) throws IOException {}
405 
406        protected void joinGroup(SocketAddress mcastaddr,
407                                  NetworkInterface netIf) throws IOException {}
408 
409        protected void leaveGroup(SocketAddress mcastaddr,
410                                  NetworkInterface netIf) throws IOException {}
411 
412        protected void close() {}
413 
414        public Object getOption(int optID) throws SocketException { return null;}
415 
416        public void setOption(int optID, Object value) throws SocketException {}
417    };
418 }
419