001    /* DatagramSocket.java -- A class to model UDP sockets
002       Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004, 2005, 2006
003       Free Software Foundation, Inc.
004    
005    This file is part of GNU Classpath.
006    
007    GNU Classpath is free software; you can redistribute it and/or modify
008    it under the terms of the GNU General Public License as published by
009    the Free Software Foundation; either version 2, or (at your option)
010    any later version.
011    
012    GNU Classpath is distributed in the hope that it will be useful, but
013    WITHOUT ANY WARRANTY; without even the implied warranty of
014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015    General Public License for more details.
016    
017    You should have received a copy of the GNU General Public License
018    along with GNU Classpath; see the file COPYING.  If not, write to the
019    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
020    02110-1301 USA.
021    
022    Linking this library statically or dynamically with other modules is
023    making a combined work based on this library.  Thus, the terms and
024    conditions of the GNU General Public License cover the whole
025    combination.
026    
027    As a special exception, the copyright holders of this library give you
028    permission to link this library with independent modules to produce an
029    executable, regardless of the license terms of these independent
030    modules, and to copy and distribute the resulting executable under
031    terms of your choice, provided that you also meet, for each linked
032    independent module, the terms and conditions of the license of that
033    module.  An independent module is a module which is not derived from
034    or based on this library.  If you modify this library, you may extend
035    this exception to your version of the library, but you are not
036    obligated to do so.  If you do not wish to do so, delete this
037    exception statement from your version. */
038    
039    package java.net;
040    
041    import gnu.classpath.SystemProperties;
042    
043    import gnu.java.net.PlainDatagramSocketImpl;
044    import gnu.java.nio.DatagramChannelImpl;
045    
046    import java.io.IOException;
047    import java.nio.channels.DatagramChannel;
048    import java.nio.channels.IllegalBlockingModeException;
049    
050    
051    /**
052     * Written using on-line Java Platform 1.2 API Specification, as well
053     * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998).
054     * Status:  Believed complete and correct.
055     */
056    /**
057     * This class models a connectionless datagram socket that sends
058     * individual packets of data across the network.  In the TCP/IP world,
059     * this means UDP.  Datagram packets do not have guaranteed delivery,
060     * or any guarantee about the order the data will be received on the
061     * remote host.
062     *
063     * @author Aaron M. Renn (arenn@urbanophile.com)
064     * @author Warren Levy (warrenl@cygnus.com)
065     * @date May 3, 1999.
066     */
067    public class DatagramSocket
068    {
069      /**
070       * This is the user DatagramSocketImplFactory for this class.  If this
071       * variable is null, a default factory is used.
072       */
073      private static DatagramSocketImplFactory factory;
074    
075      /**
076       * This is the implementation object used by this socket.
077       */
078      private DatagramSocketImpl impl;
079    
080      /**
081       * True if socket implementation was created.
082       */
083      private boolean implCreated;
084    
085      /**
086       * This is the address we are "connected" to
087       */
088      private InetAddress remoteAddress;
089    
090      /**
091       * This is the port we are "connected" to
092       */
093      private int remotePort = -1;
094    
095      /**
096       * True if socket is bound.
097       */
098      private boolean bound;
099    
100      /**
101       * Creates a <code>DatagramSocket</code> from a specified
102       * <code>DatagramSocketImpl</code> instance
103       *
104       * @param impl The <code>DatagramSocketImpl</code> the socket will be
105       * created from
106       *
107       * @since 1.4
108       */
109      protected DatagramSocket(DatagramSocketImpl impl)
110      {
111        if (impl == null)
112          throw new NullPointerException("impl may not be null");
113    
114        this.impl = impl;
115        this.remoteAddress = null;
116        this.remotePort = -1;
117      }
118    
119      /**
120       * Initializes a new instance of <code>DatagramSocket</code> that binds to
121       * a random port and every address on the local machine.
122       *
123       * @exception SocketException If an error occurs.
124       * @exception SecurityException If a security manager exists and
125       * its <code>checkListen</code> method doesn't allow the operation.
126       */
127      public DatagramSocket() throws SocketException
128      {
129        this(new InetSocketAddress(0));
130      }
131    
132      /**
133       * Initializes a new instance of <code>DatagramSocket</code> that binds to
134       * the specified port and every address on the local machine.
135       *
136       * @param port The local port number to bind to.
137       *
138       * @exception SecurityException If a security manager exists and its
139       * <code>checkListen</code> method doesn't allow the operation.
140       * @exception SocketException If an error occurs.
141       */
142      public DatagramSocket(int port) throws SocketException
143      {
144        this(new InetSocketAddress(port));
145      }
146    
147      /**
148       * Initializes a new instance of <code>DatagramSocket</code> that binds to
149       * the specified local port and address.
150       *
151       * @param port The local port number to bind to.
152       * @param addr The local address to bind to.
153       *
154       * @exception SecurityException If a security manager exists and its
155       * checkListen method doesn't allow the operation.
156       * @exception SocketException If an error occurs.
157       */
158      public DatagramSocket(int port, InetAddress addr) throws SocketException
159      {
160        this(new InetSocketAddress(addr, port));
161      }
162    
163      /**
164       * Initializes a new instance of <code>DatagramSocket</code> that binds to
165       * the specified local port and address.
166       *
167       * @param address The local address and port number to bind to.
168       *
169       * @exception SecurityException If a security manager exists and its
170       * <code>checkListen</code> method doesn't allow the operation.
171       * @exception SocketException If an error occurs.
172       *
173       * @since 1.4
174       */
175      public DatagramSocket(SocketAddress address) throws SocketException
176      {
177        String propVal = SystemProperties.getProperty("impl.prefix");
178        if (propVal == null || propVal.equals(""))
179          {
180            if (factory != null)
181              impl = factory.createDatagramSocketImpl();
182            else
183              {
184                try
185                  {
186                    impl = new PlainDatagramSocketImpl();
187                  }
188                catch (IOException ioe)
189                  {
190                    SocketException se = new SocketException();
191                    se.initCause(ioe);
192                    throw se;
193                  }
194              }
195          }
196        else
197          try
198            {
199              impl =
200                (DatagramSocketImpl) Class.forName("java.net." + propVal
201                                                   + "DatagramSocketImpl")
202                                          .newInstance();
203            }
204          catch (Exception e)
205            {
206              System.err.println("Could not instantiate class: java.net."
207                                 + propVal + "DatagramSocketImpl");
208              try
209                {
210                  impl = new PlainDatagramSocketImpl();
211                }
212              catch (IOException ioe)
213                {
214                  SocketException se = new SocketException();
215                  se.initCause(ioe);
216                  throw se;
217                }
218            }
219    
220        if (address != null)
221          bind(address);
222      }
223    
224      // This needs to be accessible from java.net.MulticastSocket
225      DatagramSocketImpl getImpl() throws SocketException
226      {
227        try
228          {
229            if (! implCreated)
230              {
231                impl.create();
232                implCreated = true;
233              }
234    
235            return impl;
236          }
237        catch (IOException e)
238          {
239            SocketException se = new SocketException();
240            se.initCause(e);
241            throw se;
242          }
243      }
244    
245      /**
246       * Closes this datagram socket.
247       */
248      public void close()
249      {
250        if (isClosed())
251          return;
252    
253        try
254          {
255            getImpl().close();
256          }
257        catch (SocketException e)
258          {
259            // Ignore this case, just close the socket in finally clause.
260          }
261        finally
262          {
263            remoteAddress = null;
264            remotePort = -1;
265            impl = null;
266          }
267    
268        try
269          {
270            if (getChannel() != null)
271              getChannel().close();
272          }
273        catch (IOException e)
274          {
275            // Do nothing.
276          }
277      }
278    
279      /**
280       * This method returns the remote address to which this socket is
281       * connected.  If this socket is not connected, then this method will
282       * return <code>null</code>.
283       *
284       * @return The remote address.
285       *
286       * @since 1.2
287       */
288      public InetAddress getInetAddress()
289      {
290        return remoteAddress;
291      }
292    
293      /**
294       * This method returns the remote port to which this socket is
295       * connected.  If this socket is not connected, then this method will
296       * return -1.
297       *
298       * @return The remote port.
299       *
300       * @since 1.2
301       */
302      public int getPort()
303      {
304        return remotePort;
305      }
306    
307      /**
308       * Returns the local address this datagram socket is bound to.
309       *
310       * @return The local address is the socket is bound or null
311       *
312       * @since 1.1
313       */
314      public InetAddress getLocalAddress()
315      {
316        if (! isBound())
317          return null;
318    
319        InetAddress localAddr;
320    
321        try
322          {
323            localAddr =
324              (InetAddress) getImpl().getOption(SocketOptions.SO_BINDADDR);
325    
326            SecurityManager s = System.getSecurityManager();
327            if (s != null)
328              s.checkConnect(localAddr.getHostAddress(), -1);
329          }
330        catch (SecurityException e)
331          {
332            localAddr = InetAddress.ANY_IF;
333          }
334        catch (SocketException e)
335          {
336            // This cannot happen as we are bound.
337            return null;
338          }
339    
340        return localAddr;
341      }
342    
343      /**
344       * Returns the local port this socket is bound to.
345       *
346       * @return The local port number.
347       */
348      public int getLocalPort()
349      {
350        if (isClosed())
351          return -1;
352    
353        try
354          {
355            return getImpl().getLocalPort();
356          }
357        catch (SocketException e)
358          {
359            // This cannot happen as we are bound.
360            return 0;
361          }
362      }
363    
364      /**
365       * Returns the value of the socket's SO_TIMEOUT setting.  If this method
366       * returns 0 then SO_TIMEOUT is disabled.
367       *
368       * @return The current timeout in milliseconds.
369       *
370       * @exception SocketException If an error occurs.
371       *
372       * @since 1.1
373       */
374      public synchronized int getSoTimeout() throws SocketException
375      {
376        if (isClosed())
377          throw new SocketException("socket is closed");
378    
379        Object buf = getImpl().getOption(SocketOptions.SO_TIMEOUT);
380    
381        if (buf instanceof Integer)
382          return ((Integer) buf).intValue();
383    
384        throw new SocketException("unexpected type");
385      }
386    
387      /**
388       * Sets the value of the socket's SO_TIMEOUT value.  A value of 0 will
389       * disable SO_TIMEOUT.  Any other value is the number of milliseconds
390       * a socket read/write will block before timing out.
391       *
392       * @param timeout The new SO_TIMEOUT value in milliseconds.
393       *
394       * @exception SocketException If an error occurs.
395       *
396       * @since 1.1
397       */
398      public synchronized void setSoTimeout(int timeout) throws SocketException
399      {
400        if (isClosed())
401          throw new SocketException("socket is closed");
402    
403        if (timeout < 0)
404          throw new IllegalArgumentException("Invalid timeout: " + timeout);
405    
406        getImpl().setOption(SocketOptions.SO_TIMEOUT, Integer.valueOf(timeout));
407      }
408    
409      /**
410       * This method returns the value of the system level socket option
411       * SO_SNDBUF, which is used by the operating system to tune buffer
412       * sizes for data transfers.
413       *
414       * @return The send buffer size.
415       *
416       * @exception SocketException If an error occurs.
417       *
418       * @since 1.2
419       */
420      public int getSendBufferSize() throws SocketException
421      {
422        if (isClosed())
423          throw new SocketException("socket is closed");
424    
425        Object buf = getImpl().getOption(SocketOptions.SO_SNDBUF);
426    
427        if (buf instanceof Integer)
428          return ((Integer) buf).intValue();
429    
430        throw new SocketException("unexpected type");
431      }
432    
433      /**
434       * This method sets the value for the system level socket option
435       * SO_SNDBUF to the specified value.  Note that valid values for this
436       * option are specific to a given operating system.
437       *
438       * @param size The new send buffer size.
439       *
440       * @exception SocketException If an error occurs.
441       * @exception IllegalArgumentException If size is 0 or negative.
442       *
443       * @since 1.2
444       */
445      public void setSendBufferSize(int size) throws SocketException
446      {
447        if (isClosed())
448          throw new SocketException("socket is closed");
449    
450        if (size < 0)
451          throw new IllegalArgumentException("Buffer size is less than 0");
452    
453        getImpl().setOption(SocketOptions.SO_SNDBUF, Integer.valueOf(size));
454      }
455    
456      /**
457       * This method returns the value of the system level socket option
458       * SO_RCVBUF, which is used by the operating system to tune buffer
459       * sizes for data transfers.
460       *
461       * @return The receive buffer size.
462       *
463       * @exception SocketException If an error occurs.
464       *
465       * @since 1.2
466       */
467      public int getReceiveBufferSize() throws SocketException
468      {
469        if (isClosed())
470          throw new SocketException("socket is closed");
471    
472        Object buf = getImpl().getOption(SocketOptions.SO_RCVBUF);
473    
474        if (buf instanceof Integer)
475          return ((Integer) buf).intValue();
476    
477        throw new SocketException("unexpected type");
478      }
479    
480      /**
481       * This method sets the value for the system level socket option
482       * SO_RCVBUF to the specified value.  Note that valid values for this
483       * option are specific to a given operating system.
484       *
485       * @param size The new receive buffer size.
486       *
487       * @exception SocketException If an error occurs.
488       * @exception IllegalArgumentException If size is 0 or negative.
489       *
490       * @since 1.2
491       */
492      public void setReceiveBufferSize(int size) throws SocketException
493      {
494        if (isClosed())
495          throw new SocketException("socket is closed");
496    
497        if (size < 0)
498          throw new IllegalArgumentException("Buffer size is less than 0");
499    
500        getImpl().setOption(SocketOptions.SO_RCVBUF, Integer.valueOf(size));
501      }
502    
503      /**
504       * This method connects this socket to the specified address and port.
505       * When a datagram socket is connected, it will only send or receive
506       * packets to and from the host to which it is connected. A multicast
507       * socket that is connected may only send and not receive packets.
508       *
509       * @param address The address to connect this socket to.
510       * @param port The port to connect this socket to.
511       *
512       * @exception IllegalArgumentException If address or port are invalid.
513       * @exception SecurityException If the caller is not allowed to send
514       * datagrams to or receive from this address and port.
515       *
516       * @since 1.2
517       */
518      public void connect(InetAddress address, int port)
519      {
520        if (address == null)
521          throw new IllegalArgumentException("Connect address may not be null");
522    
523        if ((port < 1) || (port > 65535))
524          throw new IllegalArgumentException("Port number is illegal: " + port);
525    
526        SecurityManager sm = System.getSecurityManager();
527        if (sm != null)
528          sm.checkConnect(address.getHostAddress(), port);
529    
530        try
531          {
532            getImpl().connect(address, port);
533            remoteAddress = address;
534            remotePort = port;
535          }
536        catch (SocketException e)
537          {
538            // This means simply not connected or connect not implemented.
539          }
540      }
541    
542      /**
543       * This method disconnects this socket from the address/port it was
544       * connected to.  If the socket was not connected in the first place,
545       * this method does nothing.
546       *
547       * @since 1.2
548       */
549      public void disconnect()
550      {
551        if (! isConnected())
552          return;
553    
554        try
555          {
556            getImpl().disconnect();
557          }
558        catch (SocketException e)
559          {
560            // This cannot happen as we are connected.
561          }
562        finally
563          {
564            remoteAddress = null;
565            remotePort = -1;
566          }
567      }
568    
569      /**
570       * Reads a datagram packet from the socket.  Note that this method
571       * will block until a packet is received from the network.  On return,
572       * the passed in <code>DatagramPacket</code> is populated with the data
573       * received and all the other information about the packet.
574       *
575       * @param p A <code>DatagramPacket</code> for storing the data
576       *
577       * @exception IOException If an error occurs.
578       * @exception SocketTimeoutException If setSoTimeout was previously called
579       * and the timeout has expired.
580       * @exception PortUnreachableException If the socket is connected to a
581       * currently unreachable destination. Note, there is no guarantee that the
582       * exception will be thrown.
583       * @exception IllegalBlockingModeException If this socket has an associated
584       * channel, and the channel is in non-blocking mode.
585       * @exception SecurityException If a security manager exists and its
586       * checkAccept method doesn't allow the receive.
587       */
588      public synchronized void receive(DatagramPacket p) throws IOException
589      {
590        if (isClosed())
591          throw new SocketException("socket is closed");
592    
593        if (remoteAddress != null && remoteAddress.isMulticastAddress())
594          throw new IOException
595            ("Socket connected to a multicast address my not receive");
596    
597        if (getChannel() != null && ! getChannel().isBlocking()
598            && ! ((DatagramChannelImpl) getChannel()).isInChannelOperation())
599          throw new IllegalBlockingModeException();
600    
601        DatagramPacket p2 = new DatagramPacket(p.getData(), p.getOffset(), p.maxlen);
602        getImpl().receive(p2);
603        p.length = p2.length;
604        if (p2.getAddress() != null)
605          p.setAddress(p2.getAddress());
606        if (p2.getPort() != -1)
607          p.setPort(p2.getPort());
608    
609        SecurityManager s = System.getSecurityManager();
610        if (s != null && isConnected())
611          s.checkAccept(p.getAddress().getHostAddress(), p.getPort());
612      }
613    
614      /**
615       * Sends the specified packet.  The host and port to which the packet
616       * are to be sent should be set inside the packet.
617       *
618       * @param p The datagram packet to send.
619       *
620       * @exception IOException If an error occurs.
621       * @exception SecurityException If a security manager exists and its
622       * checkMulticast or checkConnect method doesn't allow the send.
623       * @exception PortUnreachableException If the socket is connected to a
624       * currently unreachable destination. Note, there is no guarantee that the
625       * exception will be thrown.
626       * @exception IllegalBlockingModeException If this socket has an associated
627       * channel, and the channel is in non-blocking mode.
628       */
629      public void send(DatagramPacket p) throws IOException
630      {
631        if (isClosed())
632          throw new SocketException("socket is closed");
633    
634        // JDK1.2: Don't do security checks if socket is connected; see jdk1.2 api.
635        SecurityManager s = System.getSecurityManager();
636        if (s != null && ! isConnected())
637          {
638            InetAddress addr = p.getAddress();
639            if (addr.isMulticastAddress())
640              s.checkMulticast(addr);
641            else
642              s.checkConnect(addr.getHostAddress(), p.getPort());
643          }
644    
645        if (isConnected())
646          {
647            if (p.getAddress() != null
648                && (remoteAddress != p.getAddress() || remotePort != p.getPort()))
649              throw new IllegalArgumentException
650                ("DatagramPacket address does not match remote address");
651          }
652    
653        // FIXME: if this is a subclass of MulticastSocket,
654        // use getTimeToLive for TTL val.
655        if (getChannel() != null && ! getChannel().isBlocking()
656            && ! ((DatagramChannelImpl) getChannel()).isInChannelOperation())
657          throw new IllegalBlockingModeException();
658    
659        getImpl().send(p);
660      }
661    
662      /**
663       * Binds the socket to the given socket address.
664       *
665       * @param address The socket address to bind to.
666       *
667       * @exception SocketException If an error occurs.
668       * @exception SecurityException If a security manager exists and
669       * its checkListen method doesn't allow the operation.
670       * @exception IllegalArgumentException If address type is not supported.
671       *
672       * @since 1.4
673       */
674      public void bind(SocketAddress address) throws SocketException
675      {
676        if (isClosed())
677          throw new SocketException("socket is closed");
678    
679        if (address == null)
680          address = new InetSocketAddress(InetAddress.ANY_IF, 0);
681    
682        if (! (address instanceof InetSocketAddress))
683          throw new IllegalArgumentException("unsupported address type");
684    
685        InetAddress addr = ((InetSocketAddress) address).getAddress();
686        int port = ((InetSocketAddress) address).getPort();
687    
688        if (port < 0 || port > 65535)
689          throw new IllegalArgumentException("Invalid port: " + port);
690    
691        SecurityManager s = System.getSecurityManager();
692        if (s != null)
693          s.checkListen(port);
694    
695        if (addr == null)
696          addr = InetAddress.ANY_IF;
697    
698        try
699          {
700            getImpl().bind(port, addr);
701            bound = true;
702          }
703        catch (SocketException exception)
704          {
705            getImpl().close();
706            throw exception;
707          }
708        catch (RuntimeException exception)
709          {
710            getImpl().close();
711            throw exception;
712          }
713        catch (Error error)
714          {
715            getImpl().close();
716            throw error;
717          }
718      }
719    
720      /**
721       * Checks if the datagram socket is closed.
722       *
723       * @return True if socket is closed, false otherwise.
724       *
725       * @since 1.4
726       */
727      public boolean isClosed()
728      {
729        return impl == null;
730      }
731    
732      /**
733       * Returns the datagram channel assoziated with this datagram socket.
734       *
735       * @return The associated <code>DatagramChannel</code> object or null
736       *
737       * @since 1.4
738       */
739      public DatagramChannel getChannel()
740      {
741        return null;
742      }
743    
744      /**
745       * Connects the datagram socket to a specified socket address.
746       *
747       * @param address The socket address to connect to.
748       *
749       * @exception SocketException If an error occurs.
750       * @exception IllegalArgumentException If address type is not supported.
751       *
752       * @since 1.4
753       */
754      public void connect(SocketAddress address) throws SocketException
755      {
756        if (isClosed())
757          throw new SocketException("socket is closed");
758    
759        if (! (address instanceof InetSocketAddress))
760          throw new IllegalArgumentException("unsupported address type");
761    
762        InetSocketAddress tmp = (InetSocketAddress) address;
763        connect(tmp.getAddress(), tmp.getPort());
764      }
765    
766      /**
767       * Returns the binding state of the socket.
768       *
769       * @return True if socket bound, false otherwise.
770       *
771       * @since 1.4
772       */
773      public boolean isBound()
774      {
775        return bound;
776      }
777    
778      /**
779       * Returns the connection state of the socket.
780       *
781       * @return True if socket is connected, false otherwise.
782       *
783       * @since 1.4
784       */
785      public boolean isConnected()
786      {
787        return remoteAddress != null;
788      }
789    
790      /**
791       * Returns the SocketAddress of the host this socket is conneted to
792       * or null if this socket is not connected.
793       *
794       * @return The socket address of the remote host if connected or null
795       *
796       * @since 1.4
797       */
798      public SocketAddress getRemoteSocketAddress()
799      {
800        if (! isConnected())
801          return null;
802    
803        return new InetSocketAddress(remoteAddress, remotePort);
804      }
805    
806      /**
807       * Returns the local SocketAddress this socket is bound to.
808       *
809       * @return The local SocketAddress or null if the socket is not bound.
810       *
811       * @since 1.4
812       */
813      public SocketAddress getLocalSocketAddress()
814      {
815        if (! isBound())
816          return null;
817    
818        return new InetSocketAddress(getLocalAddress(), getLocalPort());
819      }
820    
821      /**
822       * Enables/Disables SO_REUSEADDR.
823       *
824       * @param on Whether or not to have SO_REUSEADDR turned on.
825       *
826       * @exception SocketException If an error occurs.
827       *
828       * @since 1.4
829       */
830      public void setReuseAddress(boolean on) throws SocketException
831      {
832        if (isClosed())
833          throw new SocketException("socket is closed");
834    
835        getImpl().setOption(SocketOptions.SO_REUSEADDR, Boolean.valueOf(on));
836      }
837    
838      /**
839       * Checks if SO_REUSEADDR is enabled.
840       *
841       * @return True if SO_REUSEADDR is set on the socket, false otherwise.
842       *
843       * @exception SocketException If an error occurs.
844       *
845       * @since 1.4
846       */
847      public boolean getReuseAddress() throws SocketException
848      {
849        if (isClosed())
850          throw new SocketException("socket is closed");
851    
852        Object buf = getImpl().getOption(SocketOptions.SO_REUSEADDR);
853    
854        if (buf instanceof Boolean)
855          return ((Boolean) buf).booleanValue();
856    
857        throw new SocketException("unexpected type");
858      }
859    
860      /**
861       * Enables/Disables SO_BROADCAST
862       *
863       * @param enable True if SO_BROADCAST should be enabled, false otherwise.
864       *
865       * @exception SocketException If an error occurs
866       *
867       * @since 1.4
868       */
869      public void setBroadcast(boolean enable) throws SocketException
870      {
871        if (isClosed())
872          throw new SocketException("socket is closed");
873    
874        getImpl().setOption(SocketOptions.SO_BROADCAST, Boolean.valueOf(enable));
875      }
876    
877      /**
878       * Checks if SO_BROADCAST is enabled
879       *
880       * @return Whether SO_BROADCAST is set
881       *
882       * @exception SocketException If an error occurs
883       *
884       * @since 1.4
885       */
886      public boolean getBroadcast() throws SocketException
887      {
888        if (isClosed())
889          throw new SocketException("socket is closed");
890    
891        Object buf = getImpl().getOption(SocketOptions.SO_BROADCAST);
892    
893        if (buf instanceof Boolean)
894          return ((Boolean) buf).booleanValue();
895    
896        throw new SocketException("unexpected type");
897      }
898    
899      /**
900       * Sets the traffic class value
901       *
902       * @param tc The traffic class
903       *
904       * @exception SocketException If an error occurs
905       * @exception IllegalArgumentException If tc value is illegal
906       *
907       * @see DatagramSocket#getTrafficClass()
908       *
909       * @since 1.4
910       */
911      public void setTrafficClass(int tc) throws SocketException
912      {
913        if (isClosed())
914          throw new SocketException("socket is closed");
915    
916        if (tc < 0 || tc > 255)
917          throw new IllegalArgumentException();
918    
919        getImpl().setOption(SocketOptions.IP_TOS, Integer.valueOf(tc));
920      }
921    
922      /**
923       * Returns the current traffic class
924       *
925       * @return The current traffic class.
926       *
927       * @see DatagramSocket#setTrafficClass(int tc)
928       *
929       * @exception SocketException If an error occurs
930       *
931       * @since 1.4
932       */
933      public int getTrafficClass() throws SocketException
934      {
935        if (isClosed())
936          throw new SocketException("socket is closed");
937    
938        Object buf = getImpl().getOption(SocketOptions.IP_TOS);
939    
940        if (buf instanceof Integer)
941          return ((Integer) buf).intValue();
942    
943        throw new SocketException("unexpected type");
944      }
945    
946      /**
947       * Sets the datagram socket implementation factory for the application
948       *
949       * @param fac The factory to set
950       *
951       * @exception IOException If an error occurs
952       * @exception SocketException If the factory is already defined
953       * @exception SecurityException If a security manager exists and its
954       * checkSetFactory method doesn't allow the operation
955       */
956      public static void setDatagramSocketImplFactory(DatagramSocketImplFactory fac)
957        throws IOException
958      {
959        if (factory != null)
960          throw new SocketException("DatagramSocketImplFactory already defined");
961    
962        SecurityManager sm = System.getSecurityManager();
963        if (sm != null)
964          sm.checkSetFactory();
965    
966        factory = fac;
967      }
968    }