DatagramSocket.java revision 7365de1056414750d0a7d1fdd26025fd247f0d04
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;
22import org.apache.harmony.luni.net.PlainDatagramSocketImpl;
23
24/**
25 * This class implements a UDP socket for sending and receiving {@code
26 * DatagramPacket}. A {@code DatagramSocket} object can be used for both
27 * endpoints of a connection for a packet delivery service.
28 *
29 * @see DatagramPacket
30 * @see DatagramSocketImplFactory
31 */
32public class DatagramSocket {
33
34    DatagramSocketImpl impl;
35
36    InetAddress address;
37
38    int port = -1;
39
40    static DatagramSocketImplFactory factory;
41
42    boolean isBound = false;
43
44    private boolean isConnected = false;
45
46    private boolean isClosed = false;
47
48    private static class Lock {
49    }
50
51    private Object lock = new Lock();
52
53    /**
54     * Constructs a UDP datagram socket which is bound to any available port on
55     * the localhost.
56     *
57     * @throws SocketException
58     *             if an error occurs while creating or binding the socket.
59     */
60    public DatagramSocket() throws SocketException {
61        this(0);
62    }
63
64    /**
65     * Constructs a UDP datagram socket which is bound to the specific port
66     * {@code aPort} on the localhost. Valid values for {@code aPort} are
67     * between 0 and 65535 inclusive.
68     *
69     * @param aPort
70     *            the port to bind on the localhost.
71     * @throws SocketException
72     *             if an error occurs while creating or binding the socket.
73     */
74    public DatagramSocket(int aPort) throws SocketException {
75        super();
76        checkListen(aPort);
77        createSocket(aPort, Inet4Address.ANY);
78    }
79
80    /**
81     * Constructs a UDP datagram socket which is bound to the specific local
82     * address {@code addr} on port {@code aPort}. Valid values for {@code
83     * aPort} are between 0 and 65535 inclusive.
84     *
85     * @param aPort
86     *            the port to bind on the localhost.
87     * @param addr
88     *            the address to bind on the localhost.
89     * @throws SocketException
90     *             if an error occurs while creating or binding the socket.
91     */
92    public DatagramSocket(int aPort, InetAddress addr) throws SocketException {
93        super();
94        checkListen(aPort);
95        createSocket(aPort, null == addr ? Inet4Address.ANY : addr);
96    }
97
98    /**
99     * Sends prior to attempting to bind the socket, checks whether the port is
100     * within the valid port range and verifies with the security manager that
101     * the port may be bound by the current context.
102     *
103     * @param aPort
104     *            the port on the localhost that is to be bound.
105     */
106    void checkListen(int aPort) {
107        if (aPort < 0 || aPort > 65535) {
108            throw new IllegalArgumentException("Port out of range: " + aPort);
109        }
110        SecurityManager security = System.getSecurityManager();
111        if (security != null) {
112            security.checkListen(aPort);
113        }
114    }
115
116    /**
117     * Closes this UDP datagram socket and all possibly associated channels.
118     */
119    // In the documentation jdk1.1.7a/guide/net/miscNet.html, this method is
120    // noted as not being synchronized.
121    public void close() {
122        isClosed = true;
123        impl.close();
124    }
125
126    /**
127     * Connects this UDP datagram socket to the specific target host with the
128     * address {@code anAdress} on port {@code aPort}. The host and port are
129     * validated, thereafter the only validation on {@code send()} and {@code
130     * receive()} is to check whether the packet address/port matches the
131     * connected target.
132     *
133     * @param anAddress
134     *            the target address of this socket.
135     * @param aPort
136     *            the target port of this socket.
137     */
138    public void connect(InetAddress anAddress, int aPort) {
139        if (anAddress == null || aPort < 0 || aPort > 65535) {
140            throw new IllegalArgumentException("Address null or destination port out of range");
141        }
142
143        synchronized (lock) {
144            if (isClosed()) {
145                return;
146            }
147            try {
148                checkClosedAndBind(true);
149            } catch (SocketException e) {
150                // Ignored
151            }
152
153            SecurityManager security = System.getSecurityManager();
154            if (security != null) {
155                if (anAddress.isMulticastAddress()) {
156                    security.checkMulticast(anAddress);
157                } else {
158                    security.checkConnect(anAddress.getHostName(), aPort);
159                }
160            }
161
162            try {
163                impl.connect(anAddress, aPort);
164            } catch (SocketException e) {
165                // not connected at the native level just do what we did before
166            }
167            address = anAddress;
168            port = aPort;
169            isConnected = true;
170        }
171    }
172
173    /**
174     * Disconnects this UDP datagram socket from the remote host. This method
175     * called on an unconnected socket does nothing.
176     */
177    public void disconnect() {
178        if (isClosed() || !isConnected()) {
179            return;
180        }
181        impl.disconnect();
182        address = null;
183        port = -1;
184        isConnected = false;
185    }
186
187    synchronized void createSocket(int aPort, InetAddress addr)
188            throws SocketException {
189        impl = factory != null ? factory.createDatagramSocketImpl()
190                : new PlainDatagramSocketImpl();
191        impl.create();
192        try {
193            impl.bind(aPort, addr);
194            isBound = true;
195        } catch (SocketException e) {
196            close();
197            throw e;
198        }
199    }
200
201    /**
202     * Gets the {@code InetAddress} instance representing the remote address to
203     * which this UDP datagram socket is connected.
204     *
205     * @return the remote address this socket is connected to or {@code null} if
206     *         this socket is not connected.
207     */
208    public InetAddress getInetAddress() {
209        return address;
210    }
211
212    /**
213     * Gets the {@code InetAddress} instance representing the bound local
214     * address of this UDP datagram socket.
215     *
216     * @return the local address to which this socket is bound to or {@code
217     *         null} if this socket is closed.
218     */
219    public InetAddress getLocalAddress() {
220        if (isClosed()) {
221            return null;
222        }
223        if (!isBound()) {
224            return Inet4Address.ANY;
225        }
226        InetAddress anAddr = impl.getLocalAddress();
227        try {
228            SecurityManager security = System.getSecurityManager();
229            if (security != null) {
230                security.checkConnect(anAddr.getHostName(), -1);
231            }
232        } catch (SecurityException e) {
233            return Inet4Address.ANY;
234        }
235        return anAddr;
236    }
237
238    /**
239     * Gets the local port which this socket is bound to.
240     *
241     * @return the local port of this socket or {@code -1} if this socket is
242     *         closed and {@code 0} if it is unbound.
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     * Gets the remote port which this socket is connected to.
256     *
257     * @return the remote port of this socket. The return value {@code -1}
258     *         indicates that this socket is not connected.
259     */
260    public int getPort() {
261        return port;
262    }
263
264    /**
265     * Indicates whether this socket is multicast or not.
266     *
267     * @return the return value is always {@code false}.
268     */
269    boolean isMulticastSocket() {
270        return false;
271    }
272
273    /**
274     * Gets the socket receive buffer size. ( {@code SocketOptions.SO_RCVBUF} )
275     *
276     * @return the input buffer size.
277     * @throws SocketException
278     *                if an error occurs while getting the option value.
279     */
280    public synchronized int getReceiveBufferSize() throws SocketException {
281        checkClosedAndBind(false);
282        return ((Integer) impl.getOption(SocketOptions.SO_RCVBUF)).intValue();
283    }
284
285    /**
286     * Gets the socket send buffer size. ( {@code SocketOptions.SO_SNDBUF} )
287     *
288     * @return the output buffer size.
289     * @throws SocketException
290     *                if an error occurs while getting the option value.
291     */
292    public synchronized int getSendBufferSize() throws SocketException {
293        checkClosedAndBind(false);
294        return ((Integer) impl.getOption(SocketOptions.SO_SNDBUF)).intValue();
295    }
296
297    /**
298     * Gets the socket {@link SocketOptions#SO_TIMEOUT receive timeout}.
299     *
300     * @throws SocketException
301     *                if an error occurs while getting the option value.
302     */
303    public synchronized int getSoTimeout() throws SocketException {
304        checkClosedAndBind(false);
305        return ((Integer) impl.getOption(SocketOptions.SO_TIMEOUT)).intValue();
306    }
307
308    /**
309     * Receives a packet from this socket and stores it in the argument {@code
310     * pack}. All fields of {@code pack} must be set according to the data
311     * received. If the received data is longer than the packet buffer size it
312     * is truncated. This method blocks until a packet is received or a timeout
313     * has expired. If a security manager exists, its {@code checkAccept} method
314     * determines whether or not a packet is discarded. Any packets from
315     * unacceptable origins are silently discarded.
316     *
317     * @param pack
318     *            the {@code DatagramPacket} to store the received data.
319     * @throws IOException
320     *                if an error occurs while receiving the packet.
321     */
322    public synchronized void receive(DatagramPacket pack) throws IOException {
323        checkClosedAndBind(true);
324
325        InetAddress senderAddr;
326        int senderPort;
327        DatagramPacket tempPack = new DatagramPacket(new byte[1], 1);
328
329        // means that we have received the packet into the temporary buffer
330        boolean copy = false;
331
332        SecurityManager security = System.getSecurityManager();
333
334        if (address != null || security != null) {
335            // The socket is connected or we need to check security permissions
336
337            // Check pack before peeking
338            if (pack == null) {
339                throw new NullPointerException();
340            }
341
342            // iterate over incoming packets
343            while (true) {
344                copy = false;
345
346                // let's get sender's address and port
347                try {
348                    senderPort = impl.peekData(tempPack);
349                    senderAddr = tempPack.getAddress();
350                } catch (SocketException e) {
351                    if (e.getMessage().equals(
352                            "The socket does not support the operation")) {
353                        // receive packet to temporary buffer
354                        tempPack = new DatagramPacket(new byte[pack.getCapacity()],
355                                pack.getCapacity());
356                        impl.receive(tempPack);
357                        // tempPack's length field is now updated, capacity is unchanged
358                        // let's extract address & port
359                        senderAddr = tempPack.getAddress();
360                        senderPort = tempPack.getPort();
361                        copy = true;
362                    } else {
363                        throw e;
364                    }
365                }
366
367                if (address == null) {
368                    // if we are not connected let's check if we are allowed to
369                    // receive packets from sender's address and port
370                    try {
371                        security.checkAccept(senderAddr.getHostName(),
372                                senderPort);
373                        // address & port are valid
374                        break;
375                    } catch (SecurityException e) {
376                        if (!copy) {
377                            // drop this packet and continue
378                            impl.receive(tempPack);
379                        }
380                    }
381                } else if (port == senderPort && address.equals(senderAddr)) {
382                    // we are connected and the packet came
383                    // from the address & port we are connected to
384                    break;
385                } else if (!copy) {
386                    // drop packet and continue
387                    impl.receive(tempPack);
388                }
389            }
390        }
391
392        if (copy) {
393            System.arraycopy(tempPack.getData(), 0, pack.getData(), pack
394                    .getOffset(), tempPack.getLength());
395            // we shouldn't update the pack's capacity field in order to be
396            // compatible with RI
397            pack.setLengthOnly(tempPack.getLength());
398            pack.setAddress(tempPack.getAddress());
399            pack.setPort(tempPack.getPort());
400        } else {
401            pack.setLength(pack.getCapacity());
402            impl.receive(pack);
403            // pack's length field is now updated by native code call;
404            // pack's capacity field is unchanged
405        }
406    }
407
408    /**
409     * Sends a packet over this socket. The packet must satisfy the security
410     * policy before it may be sent. If a security manager is installed, this
411     * method checks whether it is allowed to send this packet to the specified
412     * address.
413     *
414     * @param pack
415     *            the {@code DatagramPacket} which has to be sent.
416     * @throws IOException
417     *                if an error occurs while sending the packet.
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("Packet address mismatch with connected address");
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.getPort() == -1) {
436                    throw new NullPointerException("Destination address is null");
437                }
438                return;
439            }
440            SecurityManager security = System.getSecurityManager();
441            if (security != null) {
442                if (packAddr.isMulticastAddress()) {
443                    security.checkMulticast(packAddr);
444                } else {
445                    security.checkConnect(packAddr.getHostName(), pack
446                            .getPort());
447                }
448            }
449        }
450        impl.send(pack);
451    }
452
453    /**
454     * Sets the socket send buffer size. This buffer size determines which the
455     * maximum packet size is that can be sent over this socket. It depends on
456     * the network implementation what will happen if the packet is bigger than
457     * the buffer size. ( {@code SocketOptions.SO_SNDBUF} )
458     *
459     * @param size
460     *            the buffer size in bytes. The size must be at least one byte.
461     * @throws SocketException
462     *                if an error occurs while setting the option.
463     */
464    public synchronized void setSendBufferSize(int size) throws SocketException {
465        if (size < 1) {
466            throw new IllegalArgumentException("size < 1");
467        }
468        checkClosedAndBind(false);
469        impl.setOption(SocketOptions.SO_SNDBUF, Integer.valueOf(size));
470    }
471
472    /**
473     * Sets the socket receive buffer size. This buffer size determines which
474     * the maximum packet size is that can be received over this socket. It
475     * depends on the network implementation what will happen if the packet is
476     * bigger than the buffer size. ( {@code SocketOptions.SO_RCVBUF} )
477     *
478     * @param size
479     *            the buffer size in bytes. The size must be at least one byte.
480     * @throws SocketException
481     *                if an error occurs while setting the option.
482     */
483    public synchronized void setReceiveBufferSize(int size) throws SocketException {
484        if (size < 1) {
485            throw new IllegalArgumentException("size < 1");
486        }
487        checkClosedAndBind(false);
488        impl.setOption(SocketOptions.SO_RCVBUF, Integer.valueOf(size));
489    }
490
491    /**
492     * Sets the {@link SocketOptions#SO_TIMEOUT read timeout} in milliseconds for this socket.
493     * This receive timeout defines the period the socket will block waiting to
494     * receive data before throwing an {@code InterruptedIOException}. The value
495     * {@code 0} (default) is used to set an infinite timeout. To have effect
496     * this option must be set before the blocking method was called.
497     *
498     * @param timeout the timeout in milliseconds or 0 for no timeout.
499     * @throws SocketException
500     *                if an error occurs while setting the option.
501     */
502    public synchronized void setSoTimeout(int timeout) throws SocketException {
503        if (timeout < 0) {
504            throw new IllegalArgumentException("timeout < 0");
505        }
506        checkClosedAndBind(false);
507        impl.setOption(SocketOptions.SO_TIMEOUT, Integer.valueOf(timeout));
508    }
509
510    /**
511     * Sets the socket implementation factory. This may only be invoked once
512     * over the lifetime of the application. This factory is used to create
513     * a new datagram socket implementation. If a security manager is set its
514     * method {@code checkSetFactory()} is called to check if the operation is
515     * allowed. A {@code SecurityException} is thrown if the operation is not
516     * allowed.
517     *
518     * @param fac
519     *            the socket factory to use.
520     * @throws IOException
521     *                if the factory has already been set.
522     * @see DatagramSocketImplFactory
523     */
524    public static synchronized void setDatagramSocketImplFactory(
525            DatagramSocketImplFactory fac) throws IOException {
526        SecurityManager security = System.getSecurityManager();
527        if (security != null) {
528            security.checkSetFactory();
529        }
530        if (factory != null) {
531            throw new SocketException("Factory already set");
532        }
533        factory = fac;
534    }
535
536    /**
537     * Constructs a new {@code DatagramSocket} using the specific datagram
538     * socket implementation {@code socketImpl}. The created {@code
539     * DatagramSocket} will not be bound.
540     *
541     * @param socketImpl
542     *            the DatagramSocketImpl to use.
543     */
544    protected DatagramSocket(DatagramSocketImpl socketImpl) {
545        if (socketImpl == null) {
546            throw new NullPointerException();
547        }
548        impl = socketImpl;
549    }
550
551    /**
552     * Constructs a new {@code DatagramSocket} bound to the host/port specified
553     * by the {@code SocketAddress} {@code localAddr} or an unbound {@code
554     * DatagramSocket} if the {@code SocketAddress} is {@code null}.
555     *
556     * @param localAddr
557     *            the local machine address and port to bind to.
558     * @throws IllegalArgumentException
559     *             if the SocketAddress is not supported
560     * @throws SocketException
561     *             if a problem occurs creating or binding the socket.
562     */
563    public DatagramSocket(SocketAddress localAddr) throws SocketException {
564        if (localAddr != null) {
565            if (!(localAddr instanceof InetSocketAddress)) {
566                throw new IllegalArgumentException("Local address not an InetSocketAddress: " +
567                        localAddr.getClass());
568            }
569            checkListen(((InetSocketAddress) localAddr).getPort());
570        }
571        impl = factory != null ? factory.createDatagramSocketImpl()
572                : new PlainDatagramSocketImpl();
573        impl.create();
574        if (localAddr != null) {
575            try {
576                bind(localAddr);
577            } catch (SocketException e) {
578                close();
579                throw e;
580            }
581        }
582        // SocketOptions.SO_BROADCAST is set by default for DatagramSocket
583        setBroadcast(true);
584    }
585
586    void checkClosedAndBind(boolean bind) throws SocketException {
587        if (isClosed()) {
588            throw new SocketException("Socket is closed");
589        }
590        if (bind && !isBound()) {
591            checkListen(0);
592            impl.bind(0, Inet4Address.ANY);
593            isBound = true;
594        }
595    }
596
597    /**
598     * Binds this socket to the local address and port specified by {@code
599     * localAddr}. If this value is {@code null} any free port on a valid local
600     * address is used.
601     *
602     * @param localAddr
603     *            the local machine address and port to bind on.
604     * @throws IllegalArgumentException
605     *             if the SocketAddress is not supported
606     * @throws SocketException
607     *             if the socket is already bound or a problem occurs during
608     *             binding.
609     */
610    public void bind(SocketAddress localAddr) throws SocketException {
611        checkClosedAndBind(false);
612        int localPort = 0;
613        InetAddress addr = Inet4Address.ANY;
614        if (localAddr != null) {
615            if (!(localAddr instanceof InetSocketAddress)) {
616                throw new IllegalArgumentException("Local address not an InetSocketAddress: " +
617                        localAddr.getClass());
618            }
619            InetSocketAddress inetAddr = (InetSocketAddress) localAddr;
620            addr = inetAddr.getAddress();
621            if (addr == null) {
622                throw new SocketException("Host is unresolved: " + inetAddr.getHostName());
623            }
624            localPort = inetAddr.getPort();
625            checkListen(localPort);
626        }
627        impl.bind(localPort, addr);
628        isBound = true;
629    }
630
631    /**
632     * Connects this datagram socket to the remote host and port specified by
633     * {@code remoteAddr}. The host and port are validated, thereafter the only
634     * validation on {@code send()} and {@code receive()} is that the packet
635     * address/port matches the connected target.
636     *
637     * @param remoteAddr
638     *            the address and port of the target host.
639     * @throws SocketException
640     *                if an error occurs during connecting.
641     */
642    public void connect(SocketAddress remoteAddr) throws SocketException {
643        if (remoteAddr == null) {
644            throw new IllegalArgumentException("remoteAddr == null");
645        }
646
647        if (!(remoteAddr instanceof InetSocketAddress)) {
648            throw new IllegalArgumentException("Remote address not an InetSocketAddress: " +
649                    remoteAddr.getClass());
650        }
651
652        InetSocketAddress inetAddr = (InetSocketAddress) remoteAddr;
653        if (inetAddr.getAddress() == null) {
654            throw new SocketException("Host is unresolved: " + inetAddr.getHostName());
655        }
656
657        synchronized (lock) {
658            // make sure the socket is open
659            checkClosedAndBind(true);
660
661            SecurityManager security = System.getSecurityManager();
662            if (security != null) {
663                if (inetAddr.getAddress().isMulticastAddress()) {
664                    security.checkMulticast(inetAddr.getAddress());
665                } else {
666                    security.checkConnect(inetAddr.getAddress().getHostName(),
667                            inetAddr.getPort());
668                }
669            }
670
671            // now try to do the connection at the native level. To be
672            // compatible for the case when the address is inaddr_any we just
673            // eat the exception an act as if we are connected at the java level
674            try {
675                impl.connect(inetAddr.getAddress(), inetAddr.getPort());
676            } catch (Exception e) {
677                // not connected at the native level just do what we did before
678            }
679
680            // if we get here then we connected ok
681            address = inetAddr.getAddress();
682            port = inetAddr.getPort();
683            isConnected = true;
684        }
685    }
686
687    /**
688     * Determines whether the socket is bound to an address or not.
689     *
690     * @return {@code true} if the socket is bound, {@code false} otherwise.
691     */
692    public boolean isBound() {
693        return isBound;
694    }
695
696    /**
697     * Determines whether the socket is connected to a target host.
698     *
699     * @return {@code true} if the socket is connected, {@code false} otherwise.
700     */
701    public boolean isConnected() {
702        return isConnected;
703    }
704
705    /**
706     * Gets the address and port of the connected remote host. If this socket is
707     * not connected yet, {@code null} is returned.
708     *
709     * @return the remote socket address.
710     */
711    public SocketAddress getRemoteSocketAddress() {
712        if (!isConnected()) {
713            return null;
714        }
715        return new InetSocketAddress(getInetAddress(), getPort());
716    }
717
718    /**
719     * Gets the bound local address and port of this socket. If the socket is
720     * unbound, {@code null} is returned.
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     * Sets the socket option {@code SocketOptions.SO_REUSEADDR}. This option
733     * has to be enabled if more than one UDP socket wants to be bound to the
734     * same address. That could be needed for receiving multicast packets.
735     * <p>
736     * There is an undefined behavior if this option is set after the socket is
737     * already bound.
738     *
739     * @param reuse
740     *            the socket option value to enable or disable this option.
741     * @throws SocketException
742     *             if the socket is closed or the option could not be set.
743     */
744    public void setReuseAddress(boolean reuse) throws SocketException {
745        checkClosedAndBind(false);
746        impl.setOption(SocketOptions.SO_REUSEADDR, Boolean.valueOf(reuse));
747    }
748
749    /**
750     * Gets the state of the socket option {@code SocketOptions.SO_REUSEADDR}.
751     *
752     * @return {@code true} if the option is enabled, {@code false} otherwise.
753     * @throws SocketException
754     *             if the socket is closed or the option is invalid.
755     */
756    public boolean getReuseAddress() throws SocketException {
757        checkClosedAndBind(false);
758        return ((Boolean) impl.getOption(SocketOptions.SO_REUSEADDR))
759                .booleanValue();
760    }
761
762    /**
763     * Sets the socket option {@code SocketOptions.SO_BROADCAST}. This option
764     * must be enabled to send broadcast messages.
765     *
766     * @param broadcast
767     *            the socket option value to enable or disable this option.
768     * @throws SocketException
769     *             if the socket is closed or the option could not be set.
770     */
771    public void setBroadcast(boolean broadcast) throws SocketException {
772        checkClosedAndBind(false);
773        impl.setOption(SocketOptions.SO_BROADCAST, Boolean.valueOf(broadcast));
774    }
775
776    /**
777     * Gets the state of the socket option {@code SocketOptions.SO_BROADCAST}.
778     *
779     * @return {@code true} if the option is enabled, {@code false} otherwise.
780     * @throws SocketException
781     *             if the socket is closed or the option is invalid.
782     */
783    public boolean getBroadcast() throws SocketException {
784        checkClosedAndBind(false);
785        return ((Boolean) impl.getOption(SocketOptions.SO_BROADCAST))
786                .booleanValue();
787    }
788
789    /**
790     * Sets the {@see SocketOptions#IP_TOS} value for every packet sent by this socket.
791     *
792     * @throws SocketException
793     *             if the socket is closed or the option could not be set.
794     */
795    public void setTrafficClass(int value) throws SocketException {
796        checkClosedAndBind(false);
797        if (value < 0 || value > 255) {
798            throw new IllegalArgumentException();
799        }
800        impl.setOption(SocketOptions.IP_TOS, Integer.valueOf(value));
801    }
802
803    /**
804     * Returns this socket's {@see SocketOptions#IP_TOS} setting.
805     *
806     * @throws SocketException
807     *             if the socket is closed or the option is invalid.
808     */
809    public int getTrafficClass() throws SocketException {
810        checkClosedAndBind(false);
811        return (Integer) impl.getOption(SocketOptions.IP_TOS);
812    }
813
814    /**
815     * Gets the state of this socket.
816     *
817     * @return {@code true} if the socket is closed, {@code false} otherwise.
818     */
819    public boolean isClosed() {
820        return isClosed;
821    }
822
823    /**
824     * Gets the related DatagramChannel of this socket. This implementation
825     * returns always {@code null}.
826     *
827     * @return the related DatagramChannel or {@code null} if this socket was
828     *         not created by a {@code DatagramChannel} object.
829     */
830    public DatagramChannel getChannel() {
831        return null;
832    }
833}
834