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