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