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