DatagramSocket.java revision fdb2704414a9ed92394ada0d1395e4db86889465
1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18package java.net;
19
20import java.io.IOException;
21import java.nio.channels.DatagramChannel;
22
23//import android.net.SocketImplProvider;
24import org.apache.harmony.luni.net.SocketImplProvider;
25import org.apache.harmony.luni.platform.Platform;
26
27import org.apache.harmony.luni.util.Msg;
28
29/**
30 * This class models a socket for sending & receiving datagram packets.
31 *
32 * @see DatagramPacket
33 */
34public class DatagramSocket {
35
36    DatagramSocketImpl impl;
37
38    InetAddress address;
39
40    int port = -1;
41
42    static DatagramSocketImplFactory factory;
43
44    boolean isBound = false;
45
46    private boolean isConnected = false;
47
48    private boolean isClosed = false;
49
50    private static class Lock {
51    }
52
53    static {
54        Platform.getNetworkSystem().oneTimeInitialization(true);
55    }
56
57    private Object lock = new Lock();
58
59    /**
60     * Constructs a datagram socket, bound to any available port on the
61     * localhost.
62     *
63     * @throws SocketException
64     *             if a problem occurs creating or binding the socket
65     */
66    public DatagramSocket() throws SocketException {
67        this(0);
68    }
69
70    /**
71     * Returns a datagram socket, bound to the nominated port on the localhost.
72     *
73     * @param aPort
74     *            the port to bind on the localhost
75     *
76     * @throws SocketException
77     *             if a problem occurs creating or binding the socket
78     */
79    public DatagramSocket(int aPort) throws SocketException {
80        super();
81        checkListen(aPort);
82        createSocket(aPort, InetAddress.ANY);
83    }
84
85    /**
86     * Constructs a datagram socket, bound to the nominated localhost/port.
87     *
88     * @param aPort
89     *            the port on the localhost to bind
90     * @param addr
91     *            the address on the multihomed localhost to bind
92     *
93     * @throws SocketException
94     *             if a problem occurs creating or binding the socket
95     */
96    public DatagramSocket(int aPort, InetAddress addr) throws SocketException {
97        super();
98        checkListen(aPort);
99        createSocket(aPort, null == addr ? InetAddress.ANY : addr);
100    }
101
102    /**
103     * Sent prior to attempting to bind the socket, check that the port is
104     * within the valid port range and verify with the security manager that the
105     * port may be bound by the current context.
106     *
107     * @param aPort
108     *            the port on the localhost that is to be bound
109     */
110    void checkListen(int aPort) {
111        if (aPort < 0 || aPort > 65535) {
112            throw new IllegalArgumentException(Msg.getString("K0325", aPort)); //$NON-NLS-1$
113        }
114        SecurityManager security = System.getSecurityManager();
115        if (security != null) {
116            security.checkListen(aPort);
117        }
118    }
119
120    /**
121     * Close the socket.
122     */
123    // In the documentation jdk1.1.7a/guide/net/miscNet.html, this method is
124    // noted as not being synchronized.
125    public void close() {
126        isClosed = true;
127        impl.close();
128    }
129
130    /**
131     * Connect the datagram socket to a remote host and port. The host and port
132     * are validated, thereafter the only validation on send() and receive() is
133     * that the packet address/port matches the connected target.
134     *
135     * @param anAddress
136     *            the target address
137     * @param aPort
138     *            the target port
139     */
140    public void connect(InetAddress anAddress, int aPort) {
141        if (anAddress == null || aPort < 0 || aPort > 65535) {
142            throw new IllegalArgumentException(Msg.getString("K0032")); //$NON-NLS-1$
143        }
144
145        synchronized (lock) {
146            if (isClosed()) {
147                return;
148            }
149            try {
150                checkClosedAndBind(true);
151            } catch (SocketException e) {
152                // Ignored
153            }
154
155            SecurityManager security = System.getSecurityManager();
156            if (security != null) {
157                if (anAddress.isMulticastAddress()) {
158                    security.checkMulticast(anAddress);
159                } else {
160                    security.checkConnect(anAddress.getHostName(), aPort);
161                }
162            }
163
164            try {
165                impl.connect(anAddress, aPort);
166            } catch (SocketException e) {
167                // not connected at the native level just do what we did before
168            }
169            address = anAddress;
170            port = aPort;
171            isConnected = true;
172        }
173    }
174
175    /**
176     * 'Disconnect' the datagram socket from a remote host and port. This method
177     * may be called on an unconnected socket.
178     */
179    public void disconnect() {
180        if (isClosed() || !isConnected()) {
181            return;
182        }
183        impl.disconnect();
184        address = null;
185        port = -1;
186        isConnected = false;
187    }
188
189    synchronized void createSocket(int aPort, InetAddress addr)
190            throws SocketException {
191        impl = factory != null ? factory.createDatagramSocketImpl()
192                : SocketImplProvider.getDatagramSocketImpl();
193        impl.create();
194        try {
195            impl.bind(aPort, addr);
196            isBound = true;
197        } catch (SocketException e) {
198            close();
199            throw e;
200        }
201    }
202
203    /**
204     * Returns an {@link InetAddress} instance representing the address this
205     * socket has connected to.
206     *
207     * @return if this socket is connected, the address it is connected to. A
208     *         <code>null</code> return signifies no connection has been made.
209     */
210    public InetAddress getInetAddress() {
211        return address;
212    }
213
214    /**
215     * Returns an {@link InetAddress} instance representing the <i>local</i>
216     * address this socket is bound to.
217     *
218     * @return the local address to which the socket is bound
219     */
220    public InetAddress getLocalAddress() {
221        if (isClosed()) {
222            return null;
223        }
224        if (!isBound()) {
225            return InetAddress.ANY;
226        }
227        InetAddress anAddr = impl.getLocalAddress();
228        try {
229            SecurityManager security = System.getSecurityManager();
230            if (security != null) {
231                security.checkConnect(anAddr.getHostName(), -1);
232            }
233        } catch (SecurityException e) {
234            return InetAddress.ANY;
235        }
236        return anAddr;
237    }
238
239    /**
240     * Answer the local port to which the socket is bound.
241     *
242     * @return int local port to which the socket is bound
243     */
244    public int getLocalPort() {
245        if (isClosed()) {
246            return -1;
247        }
248        if (!isBound()) {
249            return 0;
250        }
251        return impl.getLocalPort();
252    }
253
254    /**
255     * Returns the number of the remote port this socket is connected to.
256     *
257     * @return int the remote port number that this socket has connected to. A
258     *         return of <code>-1</code> indicates that there is no connection
259     *         in place.
260     */
261    public int getPort() {
262        return port;
263    }
264
265    /**
266     * Returns whether this socket is multicast.
267     *
268     * @return Always returns false.
269     */
270    boolean isMulticastSocket() {
271        return false;
272    }
273
274    /**
275     * Answer the socket receive buffer size (SO_RCVBUF).
276     *
277     * @return int socket receive buffer size
278     *
279     * @exception SocketException
280     *                when an error occurs
281     */
282    public synchronized int getReceiveBufferSize() throws SocketException {
283        checkClosedAndBind(false);
284        return ((Integer) impl.getOption(SocketOptions.SO_RCVBUF)).intValue();
285    }
286
287    /**
288     * Answer the socket send buffer size (SO_SNDBUF).
289     *
290     * @return int socket send buffer size
291     *
292     * @exception SocketException
293     *                when an error occurs
294     */
295    public synchronized int getSendBufferSize() throws SocketException {
296        checkClosedAndBind(false);
297        return ((Integer) impl.getOption(SocketOptions.SO_SNDBUF)).intValue();
298    }
299
300    /**
301     * Answer the socket receive timeout (SO_RCVTIMEOUT), in milliseconds. Zero
302     * implies the timeout is disabled.
303     *
304     * @return int socket receive timeout
305     *
306     * @exception SocketException
307     *                when an error occurs
308     */
309    public synchronized int getSoTimeout() throws SocketException {
310        checkClosedAndBind(false);
311        return ((Integer) impl.getOption(SocketOptions.SO_TIMEOUT)).intValue();
312    }
313
314    /**
315     * Receive on this socket into the packet argument. This method blocks until
316     * a packet is received or, if a timeout has been defined, the timeout
317     * period expires. If this is a connected socket, the packet host/port are
318     * compared to the connection host/port otherwise the security manager if
319     * present is queried whether the packet host/port is acceptable. Any
320     * packets from unacceptable origins will be silently discarded. The packet
321     * fields are set according to the data received. If the received data is
322     * longer than the packet buffer, it is truncated.
323     *
324     * @param pack
325     *            the DatagramPacket to receive data into
326     *
327     * @exception java.io.IOException
328     *                If a receive error occurs.
329     */
330    public synchronized void receive(DatagramPacket pack) throws IOException {
331        checkClosedAndBind(true);
332
333        boolean secure = true;
334
335        InetAddress senderAddr = null;
336
337        int senderPort = 0;
338        DatagramPacket tempPack = new DatagramPacket(new byte[1], 1);
339        boolean copy = false;
340
341        SecurityManager security = System.getSecurityManager();
342        if (address != null || security != null) { // The socket is connected
343            // Check pack before peeking
344            if (pack == null) {
345                throw new NullPointerException();
346            }
347            secure = false;
348            while (!secure) {
349                copy = false;
350                try {
351                    senderPort = impl.peekData(tempPack);
352                    senderAddr = tempPack.getAddress();
353                } catch (SocketException e) {
354                    if (e.getMessage().equals(
355                            "The socket does not support the operation")) { //$NON-NLS-1$
356                        tempPack = new DatagramPacket(new byte[pack.length],
357                                pack.getLength());
358                        impl.receive(tempPack);
359                        senderAddr = tempPack.getAddress();
360                        senderPort = tempPack.getPort();
361                        copy = true;
362                    } else {
363                        throw e;
364                    }
365                }
366                if (address == null) {
367                    try {
368                        security.checkAccept(senderAddr.getHostName(),
369                                senderPort);
370                        if (!copy) {
371                            secure = true;
372                        }
373                        break;
374                    } catch (SecurityException e) {
375                        if (!copy) {
376                            if (tempPack == null) {
377                                tempPack = new DatagramPacket(
378                                        new byte[pack.length], pack.length);
379                            }
380                            impl.receive(tempPack);
381                        }
382                    }
383                } else if (port == senderPort && address.equals(senderAddr)) {
384                    if (!copy) {
385                        secure = true;
386                    }
387                    break;
388                } else if (!copy) {
389                    if (tempPack == null) {
390                        tempPack = new DatagramPacket(new byte[pack.length],
391                                pack.length);
392                    }
393                    impl.receive(tempPack);
394                }
395            }
396        }
397        if (copy) {
398            System.arraycopy(tempPack.getData(), 0, pack.getData(), pack
399                    .getOffset(), tempPack.getLength());
400            pack.setLength(tempPack.getLength());
401            pack.setAddress(tempPack.getAddress());
402            pack.setPort(tempPack.getPort());
403        }
404        if (secure) {
405            impl.receive(pack);
406        }
407    }
408
409    /**
410     * Send the packet on this socket. The packet must satisfy the security
411     * policy before it may be sent.
412     *
413     * @param pack
414     *            the DatagramPacket to send
415     *
416     * @exception java.io.IOException
417     *                If a send error occurs.
418     */
419    public void send(DatagramPacket pack) throws IOException {
420        checkClosedAndBind(true);
421
422        InetAddress packAddr = pack.getAddress();
423        if (address != null) { // The socket is connected
424            if (packAddr != null) {
425                if (!address.equals(packAddr) || port != pack.getPort()) {
426                    throw new IllegalArgumentException(Msg.getString("K0034")); //$NON-NLS-1$
427                }
428            } else {
429                pack.setAddress(address);
430                pack.setPort(port);
431            }
432        } else {
433            // not connected so the target address is not allowed to be null
434            if (packAddr == null) {
435                if (pack.port == -1) {
436                    // KA019 Destination address is null
437                    throw new NullPointerException(Msg.getString("KA019")); //$NON-NLS-1$
438                }
439                return;
440            }
441            SecurityManager security = System.getSecurityManager();
442            if (security != null) {
443                if (packAddr.isMulticastAddress()) {
444                    security.checkMulticast(packAddr);
445                } else {
446                    security.checkConnect(packAddr.getHostName(), pack
447                            .getPort());
448                }
449            }
450        }
451        impl.send(pack);
452    }
453
454    /**
455     * Set the socket send buffer size.
456     *
457     * @param size
458     *            the buffer size, in bytes. Must be at least one byte.
459     *
460     * @exception java.net.SocketException
461     *                If an error occurs while setting the size or the size is
462     *                invalid.
463     */
464    public synchronized void setSendBufferSize(int size) throws SocketException {
465        if (size < 1) {
466            throw new IllegalArgumentException(Msg.getString("K0035")); //$NON-NLS-1$
467        }
468        checkClosedAndBind(false);
469        impl.setOption(SocketOptions.SO_SNDBUF, Integer.valueOf(size));
470    }
471
472    /**
473     * Set the socket receive buffer size.
474     *
475     * @param size
476     *            the buffer size, in bytes. Must be at least one byte.
477     *
478     * @exception java.net.SocketException
479     *                If an error occurs while setting the size or the size is
480     *                invalid.
481     */
482    public synchronized void setReceiveBufferSize(int size)
483            throws SocketException {
484        if (size < 1) {
485            throw new IllegalArgumentException(Msg.getString("K0035")); //$NON-NLS-1$
486        }
487        checkClosedAndBind(false);
488        impl.setOption(SocketOptions.SO_RCVBUF, Integer.valueOf(size));
489    }
490
491    /**
492     * Set the SO_RCVTIMEOUT to <code>timeout</code>, in milliseconds. The
493     * receive timeout defines the period a socket will block waiting to receive
494     * data, before throwing an InterruptedIOException.
495     *
496     * @param timeout
497     *            the timeout period, in milliseconds
498     *
499     * @exception java.net.SocketException
500     *                If an error occurs while setting the timeout or the period
501     *                is invalid.
502     */
503    public synchronized void setSoTimeout(int timeout) throws SocketException {
504        if (timeout < 0) {
505            throw new IllegalArgumentException(Msg.getString("K0036")); //$NON-NLS-1$
506        }
507        checkClosedAndBind(false);
508        impl.setOption(SocketOptions.SO_TIMEOUT, Integer.valueOf(timeout));
509    }
510
511    /**
512     * Specifies the application's socket implementation factory. This may only
513     * be invoked once over the lifetime of the application.
514     *
515     * @param fac
516     *            the socket factory to set
517     * @exception IOException
518     *                thrown if the factory has already been set
519     */
520    public static synchronized void setDatagramSocketImplFactory(
521            DatagramSocketImplFactory fac) throws IOException {
522        SecurityManager security = System.getSecurityManager();
523        if (security != null) {
524            security.checkSetFactory();
525        }
526        if (factory != null) {
527            throw new SocketException(Msg.getString("K0044")); //$NON-NLS-1$
528        }
529        factory = fac;
530    }
531
532    /**
533     * Constructs a DatagramSocket using the specified DatagramSocketImpl. The
534     * DatagramSocket is not bound.
535     *
536     * @param socketImpl
537     *            the DatagramSocketImpl to use
538     */
539    protected DatagramSocket(DatagramSocketImpl socketImpl) {
540        if (socketImpl == null) {
541            throw new NullPointerException();
542        }
543        impl = socketImpl;
544    }
545
546    /**
547     * Constructs a DatagramSocket bound to the host/port specified by the
548     * SocketAddress, or an unbound DatagramSocket if the SocketAddress is null.
549     *
550     * @param localAddr
551     *            the local machine address and port to bind to
552     *
553     * @throws IllegalArgumentException
554     *             if the SocketAddress is not supported
555     * @throws SocketException
556     *             if a problem occurs creating or binding the socket
557     */
558    public DatagramSocket(SocketAddress localAddr) throws SocketException {
559        if (localAddr != null) {
560            if (!(localAddr instanceof InetSocketAddress)) {
561                throw new IllegalArgumentException(Msg.getString(
562                        "K0316", localAddr.getClass())); //$NON-NLS-1$
563            }
564            checkListen(((InetSocketAddress) localAddr).getPort());
565        }
566        impl = factory != null ? factory.createDatagramSocketImpl()
567                : SocketImplProvider.getDatagramSocketImpl();
568        impl.create();
569        if (localAddr != null) {
570            try {
571                bind(localAddr);
572            } catch (SocketException e) {
573                close();
574                throw e;
575            }
576        }
577        // SocketOptions.SO_BROADCAST is set by default for DatagramSocket
578        setBroadcast(true);
579    }
580
581    void checkClosedAndBind(boolean bind) throws SocketException {
582        if (isClosed()) {
583            throw new SocketException(Msg.getString("K003d")); //$NON-NLS-1$
584        }
585        if (bind && !isBound()) {
586            checkListen(0);
587            impl.bind(0, InetAddress.ANY);
588            isBound = true;
589        }
590    }
591
592    /**
593     * Bind the DatagramSocket to the nominated local host/port.
594     *
595     * @param localAddr
596     *            the local machine address and port to bind on
597     *
598     * @throws IllegalArgumentException
599     *             if the SocketAddress is not supported
600     * @throws SocketException
601     *             if the socket is already bound, or a problem occurs during
602     *             the bind
603     */
604    public void bind(SocketAddress localAddr) throws SocketException {
605        checkClosedAndBind(false);
606        int localPort = 0;
607        InetAddress addr = InetAddress.ANY;
608        if (localAddr != null) {
609            if (!(localAddr instanceof InetSocketAddress)) {
610                throw new IllegalArgumentException(Msg.getString(
611                        "K0316", localAddr.getClass())); //$NON-NLS-1$
612            }
613            InetSocketAddress inetAddr = (InetSocketAddress) localAddr;
614            addr = inetAddr.getAddress();
615            if (addr == null) {
616                throw new SocketException(Msg.getString(
617                        "K0317", inetAddr.getHostName())); //$NON-NLS-1$
618            }
619            localPort = inetAddr.getPort();
620            checkListen(localPort);
621        }
622        impl.bind(localPort, addr);
623        isBound = true;
624    }
625
626    /**
627     * Connect the datagram socket to a remote host and port. The host and port
628     * are validated, thereafter the only validation on send() and receive() is
629     * that the packet address/port matches the connected target.
630     *
631     * @param remoteAddr
632     *            the target address and port
633     *
634     * @exception SocketException
635     *                if a problem occurs during the connect
636     */
637    public void connect(SocketAddress remoteAddr) throws SocketException {
638        if (remoteAddr == null) {
639            throw new IllegalArgumentException(Msg.getString("K0318")); //$NON-NLS-1$
640        }
641
642        if (!(remoteAddr instanceof InetSocketAddress)) {
643            throw new IllegalArgumentException(Msg.getString(
644                    "K0316", remoteAddr.getClass())); //$NON-NLS-1$
645        }
646
647        InetSocketAddress inetAddr = (InetSocketAddress) remoteAddr;
648        if (inetAddr.getAddress() == null) {
649            throw new SocketException(Msg.getString(
650                    "K0317", inetAddr.getHostName())); //$NON-NLS-1$
651        }
652
653        synchronized (lock) {
654            // make sure the socket is open
655            checkClosedAndBind(true);
656
657            SecurityManager security = System.getSecurityManager();
658            if (security != null) {
659                if (inetAddr.getAddress().isMulticastAddress()) {
660                    security.checkMulticast(inetAddr.getAddress());
661                } else {
662                    security.checkConnect(inetAddr.getAddress().getHostName(),
663                            inetAddr.getPort());
664                }
665            }
666
667            // now try to do the connection at the native level. To be
668            // compatible for the case when the address is inaddr_any we just
669            // eat the exception an act as if we are connected at the java level
670            try {
671                impl.connect(inetAddr.getAddress(), inetAddr.getPort());
672            } catch (Exception e) {
673                // not connected at the native level just do what we did before
674            }
675
676            // if we get here then we connected ok
677            address = inetAddr.getAddress();
678            port = inetAddr.getPort();
679            isConnected = true;
680        }
681    }
682
683    /**
684     * Return if the socket is bound to a local address and port.
685     *
686     * @return <code>true</code> if the socket is bound to a local address,
687     *         <code>false</code> otherwise.
688     */
689    public boolean isBound() {
690        return isBound;
691    }
692
693    /**
694     * Return if the socket is connected.
695     *
696     * @return <code>true</code> if the socket is connected,
697     *         <code>false</code> otherwise.
698     */
699    public boolean isConnected() {
700        return isConnected;
701    }
702
703    /**
704     * Answer the remote SocketAddress for this socket, or null if the socket is
705     * not connected.
706     *
707     * @return the remote socket address
708     */
709    public SocketAddress getRemoteSocketAddress() {
710        if (!isConnected()) {
711            return null;
712        }
713        return new InetSocketAddress(getInetAddress(), getPort());
714    }
715
716    /**
717     * Answer the local SocketAddress for this socket, or null if the socket is
718     * not bound.
719     * <p>
720     * This is useful on multihomed hosts.
721     *
722     * @return the local socket address
723     */
724    public SocketAddress getLocalSocketAddress() {
725        if (!isBound()) {
726            return null;
727        }
728        return new InetSocketAddress(getLocalAddress(), getLocalPort());
729    }
730
731    /**
732     * Set the SO_REUSEADDR socket option.
733     *
734     * @param reuse
735     *            the socket SO_REUSEADDR option setting
736     *
737     * @throws SocketException
738     *             if the socket is closed or the option is invalid.
739     */
740    public void setReuseAddress(boolean reuse) throws SocketException {
741        checkClosedAndBind(false);
742        impl.setOption(SocketOptions.SO_REUSEADDR, reuse ? Boolean.TRUE
743                : Boolean.FALSE);
744    }
745
746    /**
747     * Get the state of the SO_REUSEADDR socket option.
748     *
749     * @return <code>true</code> if the SO_REUSEADDR is enabled,
750     *         <code>false</code> otherwise.
751     *
752     * @throws SocketException
753     *             if the socket is closed or the option is invalid.
754     */
755    public boolean getReuseAddress() throws SocketException {
756        checkClosedAndBind(false);
757        return ((Boolean) impl.getOption(SocketOptions.SO_REUSEADDR))
758                .booleanValue();
759    }
760
761    /**
762     * Set the SO_BROADCAST socket option.
763     *
764     * @param broadcast
765     *            the socket SO_BROADCAST option setting
766     *
767     * @throws SocketException
768     *             if the socket is closed or the option is invalid.
769     */
770    public void setBroadcast(boolean broadcast) throws SocketException {
771        checkClosedAndBind(false);
772        impl.setOption(SocketOptions.SO_BROADCAST, broadcast ? Boolean.TRUE
773                : Boolean.FALSE);
774    }
775
776    /**
777     * Get the state of the SO_BROADCAST socket option.
778     *
779     * @return <code>true</code> if the SO_BROADCAST is enabled,
780     *         <code>false</code> otherwise.
781     *
782     * @throws SocketException
783     *             if the socket is closed or the option is invalid.
784     */
785    public boolean getBroadcast() throws SocketException {
786        checkClosedAndBind(false);
787        return ((Boolean) impl.getOption(SocketOptions.SO_BROADCAST))
788                .booleanValue();
789    }
790
791    /**
792     * Set the IP_TOS socket option.
793     *
794     * @param value
795     *            the socket IP_TOS setting
796     *
797     * @throws SocketException
798     *             if the socket is closed or the option is invalid.
799     */
800    public void setTrafficClass(int value) throws SocketException {
801        checkClosedAndBind(false);
802        if (value < 0 || value > 255) {
803            throw new IllegalArgumentException();
804        }
805        impl.setOption(SocketOptions.IP_TOS, Integer.valueOf(value));
806    }
807
808    /**
809     * Get the IP_TOS socket option.
810     *
811     * @return the IP_TOS socket option value
812     *
813     * @throws SocketException
814     *             if the option is invalid
815     */
816    public int getTrafficClass() throws SocketException {
817        checkClosedAndBind(false);
818        return ((Number) impl.getOption(SocketOptions.IP_TOS)).intValue();
819    }
820
821    /**
822     * Return if the socket is closed.
823     *
824     * @return <code>true</code> if the socket is closed, <code>false</code>
825     *         otherwise.
826     */
827    public boolean isClosed() {
828        return isClosed;
829    }
830
831    /**
832     * if DatagramSocket is created by a DatagramChannel, returns the related
833     * DatagramChannel
834     *
835     * @return the related DatagramChannel if any
836     */
837    public DatagramChannel getChannel() {
838        return null;
839    }
840}
841