DatagramSocket.java revision 1294cc5f777bce3fbc88e65d8c67cdf9b8d433c1
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, (addr == null) ? 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                throw new NullPointerException("Destination address is null");
433            }
434            SecurityManager security = System.getSecurityManager();
435            if (security != null) {
436                if (packAddr.isMulticastAddress()) {
437                    security.checkMulticast(packAddr);
438                } else {
439                    security.checkConnect(packAddr.getHostName(), pack.getPort());
440                }
441            }
442        }
443        impl.send(pack);
444    }
445
446    /**
447     * Sets the network interface used by this socket.  Any packets sent
448     * via this socket are transmitted via the specified interface.  Any
449     * packets received by this socket will come from the specified
450     * interface.  Broadcast datagrams received on this interface will
451     * be processed by this socket. {@see SocketOptions#SO_BINDTODEVICE}
452     *
453     * @hide
454     */
455    public void setNetworkInterface(NetworkInterface netInterface) throws SocketException {
456        if (netInterface == null) {
457            throw new NullPointerException("networkInterface == null");
458        }
459
460        impl.setOption(SocketOptions.SO_BINDTODEVICE,
461            Integer.valueOf(netInterface.getIndex()));
462    }
463
464    /**
465     * Sets the socket send buffer size. This buffer size determines which the
466     * maximum packet size is that can be sent over this socket. It depends on
467     * the network implementation what will happen if the packet is bigger than
468     * the buffer size. ( {@code SocketOptions.SO_SNDBUF} )
469     *
470     * @param size
471     *            the buffer size in bytes. The size must be at least one byte.
472     * @throws SocketException
473     *                if an error occurs while setting the option.
474     */
475    public synchronized void setSendBufferSize(int size) throws SocketException {
476        if (size < 1) {
477            throw new IllegalArgumentException("size < 1");
478        }
479        checkClosedAndBind(false);
480        impl.setOption(SocketOptions.SO_SNDBUF, Integer.valueOf(size));
481    }
482
483    /**
484     * Sets the socket receive buffer size. This buffer size determines which
485     * the maximum packet size is that can be received over this socket. It
486     * depends on the network implementation what will happen if the packet is
487     * bigger than the buffer size. ( {@code SocketOptions.SO_RCVBUF} )
488     *
489     * @param size
490     *            the buffer size in bytes. The size must be at least one byte.
491     * @throws SocketException
492     *                if an error occurs while setting the option.
493     */
494    public synchronized void setReceiveBufferSize(int size) throws SocketException {
495        if (size < 1) {
496            throw new IllegalArgumentException("size < 1");
497        }
498        checkClosedAndBind(false);
499        impl.setOption(SocketOptions.SO_RCVBUF, Integer.valueOf(size));
500    }
501
502    /**
503     * Sets the {@link SocketOptions#SO_TIMEOUT read timeout} in milliseconds for this socket.
504     * This receive timeout defines the period the socket will block waiting to
505     * receive data before throwing an {@code InterruptedIOException}. The value
506     * {@code 0} (default) is used to set an infinite timeout. To have effect
507     * this option must be set before the blocking method was called.
508     *
509     * @param timeout the timeout in milliseconds or 0 for no timeout.
510     * @throws SocketException
511     *                if an error occurs while setting the option.
512     */
513    public synchronized void setSoTimeout(int timeout) throws SocketException {
514        if (timeout < 0) {
515            throw new IllegalArgumentException("timeout < 0");
516        }
517        checkClosedAndBind(false);
518        impl.setOption(SocketOptions.SO_TIMEOUT, Integer.valueOf(timeout));
519    }
520
521    /**
522     * Sets the socket implementation factory. This may only be invoked once
523     * over the lifetime of the application. This factory is used to create
524     * a new datagram socket implementation. If a security manager is set its
525     * method {@code checkSetFactory()} is called to check if the operation is
526     * allowed. A {@code SecurityException} is thrown if the operation is not
527     * allowed.
528     *
529     * @param fac
530     *            the socket factory to use.
531     * @throws IOException
532     *                if the factory has already been set.
533     * @see DatagramSocketImplFactory
534     */
535    public static synchronized void setDatagramSocketImplFactory(
536            DatagramSocketImplFactory fac) throws IOException {
537        SecurityManager security = System.getSecurityManager();
538        if (security != null) {
539            security.checkSetFactory();
540        }
541        if (factory != null) {
542            throw new SocketException("Factory already set");
543        }
544        factory = fac;
545    }
546
547    /**
548     * Constructs a new {@code DatagramSocket} using the specific datagram
549     * socket implementation {@code socketImpl}. The created {@code
550     * DatagramSocket} will not be bound.
551     *
552     * @param socketImpl
553     *            the DatagramSocketImpl to use.
554     */
555    protected DatagramSocket(DatagramSocketImpl socketImpl) {
556        if (socketImpl == null) {
557            throw new NullPointerException();
558        }
559        impl = socketImpl;
560    }
561
562    /**
563     * Constructs a new {@code DatagramSocket} bound to the host/port specified
564     * by the {@code SocketAddress} {@code localAddr} or an unbound {@code
565     * DatagramSocket} if the {@code SocketAddress} is {@code null}.
566     *
567     * @param localAddr
568     *            the local machine address and port to bind to.
569     * @throws IllegalArgumentException
570     *             if the SocketAddress is not supported
571     * @throws SocketException
572     *             if a problem occurs creating or binding the socket.
573     */
574    public DatagramSocket(SocketAddress localAddr) throws SocketException {
575        if (localAddr != null) {
576            if (!(localAddr instanceof InetSocketAddress)) {
577                throw new IllegalArgumentException("Local address not an InetSocketAddress: " +
578                        localAddr.getClass());
579            }
580            checkListen(((InetSocketAddress) localAddr).getPort());
581        }
582        impl = factory != null ? factory.createDatagramSocketImpl()
583                : new PlainDatagramSocketImpl();
584        impl.create();
585        if (localAddr != null) {
586            try {
587                bind(localAddr);
588            } catch (SocketException e) {
589                close();
590                throw e;
591            }
592        }
593        // SocketOptions.SO_BROADCAST is set by default for DatagramSocket
594        setBroadcast(true);
595    }
596
597    void checkClosedAndBind(boolean bind) throws SocketException {
598        if (isClosed()) {
599            throw new SocketException("Socket is closed");
600        }
601        if (bind && !isBound()) {
602            checkListen(0);
603            impl.bind(0, Inet4Address.ANY);
604            isBound = true;
605        }
606    }
607
608    /**
609     * Binds this socket to the local address and port specified by {@code
610     * localAddr}. If this value is {@code null} any free port on a valid local
611     * address is used.
612     *
613     * @param localAddr
614     *            the local machine address and port to bind on.
615     * @throws IllegalArgumentException
616     *             if the SocketAddress is not supported
617     * @throws SocketException
618     *             if the socket is already bound or a problem occurs during
619     *             binding.
620     */
621    public void bind(SocketAddress localAddr) throws SocketException {
622        checkClosedAndBind(false);
623        int localPort = 0;
624        InetAddress addr = Inet4Address.ANY;
625        if (localAddr != null) {
626            if (!(localAddr instanceof InetSocketAddress)) {
627                throw new IllegalArgumentException("Local address not an InetSocketAddress: " +
628                        localAddr.getClass());
629            }
630            InetSocketAddress inetAddr = (InetSocketAddress) localAddr;
631            addr = inetAddr.getAddress();
632            if (addr == null) {
633                throw new SocketException("Host is unresolved: " + inetAddr.getHostName());
634            }
635            localPort = inetAddr.getPort();
636            checkListen(localPort);
637        }
638        impl.bind(localPort, addr);
639        isBound = true;
640    }
641
642    /**
643     * Connects this datagram socket to the remote host and port specified by
644     * {@code remoteAddr}. The host and port are validated, thereafter the only
645     * validation on {@code send()} and {@code receive()} is that the packet
646     * address/port matches the connected target.
647     *
648     * @param remoteAddr
649     *            the address and port of the target host.
650     * @throws SocketException
651     *                if an error occurs during connecting.
652     */
653    public void connect(SocketAddress remoteAddr) throws SocketException {
654        if (remoteAddr == null) {
655            throw new IllegalArgumentException("remoteAddr == null");
656        }
657
658        if (!(remoteAddr instanceof InetSocketAddress)) {
659            throw new IllegalArgumentException("Remote address not an InetSocketAddress: " +
660                    remoteAddr.getClass());
661        }
662
663        InetSocketAddress inetAddr = (InetSocketAddress) remoteAddr;
664        if (inetAddr.getAddress() == null) {
665            throw new SocketException("Host is unresolved: " + inetAddr.getHostName());
666        }
667
668        synchronized (lock) {
669            // make sure the socket is open
670            checkClosedAndBind(true);
671
672            SecurityManager security = System.getSecurityManager();
673            if (security != null) {
674                if (inetAddr.getAddress().isMulticastAddress()) {
675                    security.checkMulticast(inetAddr.getAddress());
676                } else {
677                    security.checkConnect(inetAddr.getAddress().getHostName(),
678                            inetAddr.getPort());
679                }
680            }
681
682            // now try to do the connection at the native level. To be
683            // compatible for the case when the address is inaddr_any we just
684            // eat the exception an act as if we are connected at the java level
685            try {
686                impl.connect(inetAddr.getAddress(), inetAddr.getPort());
687            } catch (Exception e) {
688                // not connected at the native level just do what we did before
689            }
690
691            // if we get here then we connected ok
692            address = inetAddr.getAddress();
693            port = inetAddr.getPort();
694            isConnected = true;
695        }
696    }
697
698    /**
699     * Determines whether the socket is bound to an address or not.
700     *
701     * @return {@code true} if the socket is bound, {@code false} otherwise.
702     */
703    public boolean isBound() {
704        return isBound;
705    }
706
707    /**
708     * Determines whether the socket is connected to a target host.
709     *
710     * @return {@code true} if the socket is connected, {@code false} otherwise.
711     */
712    public boolean isConnected() {
713        return isConnected;
714    }
715
716    /**
717     * Gets the address and port of the connected remote host. If this socket is
718     * not connected yet, {@code null} is returned.
719     *
720     * @return the remote socket address.
721     */
722    public SocketAddress getRemoteSocketAddress() {
723        if (!isConnected()) {
724            return null;
725        }
726        return new InetSocketAddress(getInetAddress(), getPort());
727    }
728
729    /**
730     * Gets the bound local address and port of this socket. If the socket is
731     * unbound, {@code null} is returned.
732     *
733     * @return the local socket address.
734     */
735    public SocketAddress getLocalSocketAddress() {
736        if (!isBound()) {
737            return null;
738        }
739        return new InetSocketAddress(getLocalAddress(), getLocalPort());
740    }
741
742    /**
743     * Sets the socket option {@code SocketOptions.SO_REUSEADDR}. This option
744     * has to be enabled if more than one UDP socket wants to be bound to the
745     * same address. That could be needed for receiving multicast packets.
746     * <p>
747     * There is an undefined behavior if this option is set after the socket is
748     * already bound.
749     *
750     * @param reuse
751     *            the socket option value to enable or disable this option.
752     * @throws SocketException
753     *             if the socket is closed or the option could not be set.
754     */
755    public void setReuseAddress(boolean reuse) throws SocketException {
756        checkClosedAndBind(false);
757        impl.setOption(SocketOptions.SO_REUSEADDR, Boolean.valueOf(reuse));
758    }
759
760    /**
761     * Gets the state of the socket option {@code SocketOptions.SO_REUSEADDR}.
762     *
763     * @return {@code true} if the option is enabled, {@code false} otherwise.
764     * @throws SocketException
765     *             if the socket is closed or the option is invalid.
766     */
767    public boolean getReuseAddress() throws SocketException {
768        checkClosedAndBind(false);
769        return ((Boolean) impl.getOption(SocketOptions.SO_REUSEADDR))
770                .booleanValue();
771    }
772
773    /**
774     * Sets the socket option {@code SocketOptions.SO_BROADCAST}. This option
775     * must be enabled to send broadcast messages.
776     *
777     * @param broadcast
778     *            the socket option value to enable or disable this option.
779     * @throws SocketException
780     *             if the socket is closed or the option could not be set.
781     */
782    public void setBroadcast(boolean broadcast) throws SocketException {
783        checkClosedAndBind(false);
784        impl.setOption(SocketOptions.SO_BROADCAST, Boolean.valueOf(broadcast));
785    }
786
787    /**
788     * Gets the state of the socket option {@code SocketOptions.SO_BROADCAST}.
789     *
790     * @return {@code true} if the option is enabled, {@code false} otherwise.
791     * @throws SocketException
792     *             if the socket is closed or the option is invalid.
793     */
794    public boolean getBroadcast() throws SocketException {
795        checkClosedAndBind(false);
796        return ((Boolean) impl.getOption(SocketOptions.SO_BROADCAST))
797                .booleanValue();
798    }
799
800    /**
801     * Sets the {@see SocketOptions#IP_TOS} value for every packet sent by this socket.
802     *
803     * @throws SocketException
804     *             if the socket is closed or the option could not be set.
805     */
806    public void setTrafficClass(int value) throws SocketException {
807        checkClosedAndBind(false);
808        if (value < 0 || value > 255) {
809            throw new IllegalArgumentException();
810        }
811        impl.setOption(SocketOptions.IP_TOS, Integer.valueOf(value));
812    }
813
814    /**
815     * Returns this socket's {@see SocketOptions#IP_TOS} setting.
816     *
817     * @throws SocketException
818     *             if the socket is closed or the option is invalid.
819     */
820    public int getTrafficClass() throws SocketException {
821        checkClosedAndBind(false);
822        return (Integer) impl.getOption(SocketOptions.IP_TOS);
823    }
824
825    /**
826     * Gets the state of this socket.
827     *
828     * @return {@code true} if the socket is closed, {@code false} otherwise.
829     */
830    public boolean isClosed() {
831        return isClosed;
832    }
833
834    /**
835     * Returns this socket's {@code DatagramChannel}, if one exists. A channel is
836     * available only if this socket wraps a channel. (That is, you can go from a
837     * channel to a socket and back again, but you can't go from an arbitrary socket to a channel.)
838     * In practice, this means that the socket must have been created by
839     * {@link java.nio.channels.DatagramChannel#open}.
840     */
841    public DatagramChannel getChannel() {
842        return null;
843    }
844}
845