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