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
005This file is part of GNU Classpath.
006
007GNU Classpath is free software; you can redistribute it and/or modify
008it under the terms of the GNU General Public License as published by
009the Free Software Foundation; either version 2, or (at your option)
010any later version.
011
012GNU Classpath is distributed in the hope that it will be useful, but
013WITHOUT ANY WARRANTY; without even the implied warranty of
014MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015General Public License for more details.
016
017You should have received a copy of the GNU General Public License
018along with GNU Classpath; see the file COPYING.  If not, write to the
019Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02002110-1301 USA.
021
022Linking this library statically or dynamically with other modules is
023making a combined work based on this library.  Thus, the terms and
024conditions of the GNU General Public License cover the whole
025combination.
026
027As a special exception, the copyright holders of this library give you
028permission to link this library with independent modules to produce an
029executable, regardless of the license terms of these independent
030modules, and to copy and distribute the resulting executable under
031terms of your choice, provided that you also meet, for each linked
032independent module, the terms and conditions of the license of that
033module.  An independent module is a module which is not derived from
034or based on this library.  If you modify this library, you may extend
035this exception to your version of the library, but you are not
036obligated to do so.  If you do not wish to do so, delete this
037exception statement from your version. */
038
039package java.net;
040
041import gnu.classpath.SystemProperties;
042
043import gnu.java.net.PlainDatagramSocketImpl;
044import gnu.java.nio.DatagramChannelImpl;
045
046import java.io.IOException;
047import java.nio.channels.DatagramChannel;
048import 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 */
067public 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      {
529        if (address.isMulticastAddress())
530          sm.checkMulticast(address);
531        else
532          {
533            sm.checkConnect(address.getHostAddress(), port);
534            sm.checkAccept(address.getHostAddress(), port);
535          }
536      }
537
538    if (!isBound())
539      {
540        try
541          {
542            bind(new InetSocketAddress(0));
543          }
544        catch (SocketException e)
545          {
546            throw new Error("Binding socket failed.", e);
547          }
548      }
549
550    try
551      {
552        getImpl().connect(address, port);
553        remoteAddress = address;
554        remotePort = port;
555      }
556    catch (SocketException e)
557      {
558        // This means simply not connected or connect not implemented.
559      }
560  }
561
562  /**
563   * This method disconnects this socket from the address/port it was
564   * connected to.  If the socket was not connected in the first place,
565   * this method does nothing.
566   *
567   * @since 1.2
568   */
569  public void disconnect()
570  {
571    if (! isConnected())
572      return;
573
574    try
575      {
576        getImpl().disconnect();
577      }
578    catch (SocketException e)
579      {
580        // This cannot happen as we are connected.
581      }
582    finally
583      {
584        remoteAddress = null;
585        remotePort = -1;
586      }
587  }
588
589  /**
590   * Reads a datagram packet from the socket.  Note that this method
591   * will block until a packet is received from the network.  On return,
592   * the passed in <code>DatagramPacket</code> is populated with the data
593   * received and all the other information about the packet.
594   *
595   * @param p A <code>DatagramPacket</code> for storing the data
596   *
597   * @exception IOException If an error occurs.
598   * @exception SocketTimeoutException If setSoTimeout was previously called
599   * and the timeout has expired.
600   * @exception PortUnreachableException If the socket is connected to a
601   * currently unreachable destination. Note, there is no guarantee that the
602   * exception will be thrown.
603   * @exception IllegalBlockingModeException If this socket has an associated
604   * channel, and the channel is in non-blocking mode.
605   * @exception SecurityException If a security manager exists and its
606   * checkAccept method doesn't allow the receive.
607   */
608  public synchronized void receive(DatagramPacket p) throws IOException
609  {
610    if (isClosed())
611      throw new SocketException("socket is closed");
612
613    if (remoteAddress != null && remoteAddress.isMulticastAddress())
614      throw new IOException
615        ("Socket connected to a multicast address my not receive");
616
617    if (getChannel() != null && ! getChannel().isBlocking()
618        && ! ((DatagramChannelImpl) getChannel()).isInChannelOperation())
619      throw new IllegalBlockingModeException();
620
621    DatagramPacket p2 = new DatagramPacket(p.getData(), p.getOffset(), p.maxlen);
622    getImpl().receive(p2);
623    p.length = p2.length;
624    if (p2.getAddress() != null)
625      p.setAddress(p2.getAddress());
626    if (p2.getPort() != -1)
627      p.setPort(p2.getPort());
628
629    SecurityManager s = System.getSecurityManager();
630    if (s != null && isConnected())
631      s.checkAccept(p.getAddress().getHostAddress(), p.getPort());
632  }
633
634  /**
635   * Sends the specified packet.  The host and port to which the packet
636   * are to be sent should be set inside the packet.
637   *
638   * @param p The datagram packet to send.
639   *
640   * @exception IOException If an error occurs.
641   * @exception SecurityException If a security manager exists and its
642   * checkMulticast or checkConnect method doesn't allow the send.
643   * @exception PortUnreachableException If the socket is connected to a
644   * currently unreachable destination. Note, there is no guarantee that the
645   * exception will be thrown.
646   * @exception IllegalBlockingModeException If this socket has an associated
647   * channel, and the channel is in non-blocking mode.
648   */
649  public void send(DatagramPacket p) throws IOException
650  {
651    if (isClosed())
652      throw new SocketException("socket is closed");
653
654    // JDK1.2: Don't do security checks if socket is connected; see jdk1.2 api.
655    SecurityManager s = System.getSecurityManager();
656    if (s != null && ! isConnected())
657      {
658        InetAddress addr = p.getAddress();
659        if (addr.isMulticastAddress())
660          s.checkMulticast(addr);
661        else
662          s.checkConnect(addr.getHostAddress(), p.getPort());
663      }
664
665    if (isConnected())
666      {
667        if (p.getAddress() != null
668            && (remoteAddress != p.getAddress() || remotePort != p.getPort()))
669          throw new IllegalArgumentException
670            ("DatagramPacket address does not match remote address");
671      }
672
673    // FIXME: if this is a subclass of MulticastSocket,
674    // use getTimeToLive for TTL val.
675    if (getChannel() != null && ! getChannel().isBlocking()
676        && ! ((DatagramChannelImpl) getChannel()).isInChannelOperation())
677      throw new IllegalBlockingModeException();
678
679    getImpl().send(p);
680  }
681
682  /**
683   * Binds the socket to the given socket address.
684   *
685   * @param address The socket address to bind to.
686   *
687   * @exception SocketException If an error occurs.
688   * @exception SecurityException If a security manager exists and
689   * its checkListen method doesn't allow the operation.
690   * @exception IllegalArgumentException If address type is not supported.
691   *
692   * @since 1.4
693   */
694  public void bind(SocketAddress address) throws SocketException
695  {
696    if (isClosed())
697      throw new SocketException("socket is closed");
698
699    if (address == null)
700      address = new InetSocketAddress(InetAddress.ANY_IF, 0);
701
702    if (! (address instanceof InetSocketAddress))
703      throw new IllegalArgumentException("unsupported address type");
704
705    InetAddress addr = ((InetSocketAddress) address).getAddress();
706    int port = ((InetSocketAddress) address).getPort();
707
708    if (port < 0 || port > 65535)
709      throw new IllegalArgumentException("Invalid port: " + port);
710
711    SecurityManager s = System.getSecurityManager();
712    if (s != null)
713      s.checkListen(port);
714
715    if (addr == null)
716      addr = InetAddress.ANY_IF;
717
718    try
719      {
720        getImpl().bind(port, addr);
721        bound = true;
722      }
723    catch (SocketException exception)
724      {
725        getImpl().close();
726        throw exception;
727      }
728    catch (RuntimeException exception)
729      {
730        getImpl().close();
731        throw exception;
732      }
733    catch (Error error)
734      {
735        getImpl().close();
736        throw error;
737      }
738  }
739
740  /**
741   * Checks if the datagram socket is closed.
742   *
743   * @return True if socket is closed, false otherwise.
744   *
745   * @since 1.4
746   */
747  public boolean isClosed()
748  {
749    return impl == null;
750  }
751
752  /**
753   * Returns the datagram channel assoziated with this datagram socket.
754   *
755   * @return The associated <code>DatagramChannel</code> object or null
756   *
757   * @since 1.4
758   */
759  public DatagramChannel getChannel()
760  {
761    return null;
762  }
763
764  /**
765   * Connects the datagram socket to a specified socket address.
766   *
767   * @param address The socket address to connect to.
768   *
769   * @exception SocketException If an error occurs.
770   * @exception IllegalArgumentException If address type is not supported.
771   *
772   * @since 1.4
773   */
774  public void connect(SocketAddress address) throws SocketException
775  {
776    if (isClosed())
777      throw new SocketException("socket is closed");
778
779    if (! (address instanceof InetSocketAddress))
780      throw new IllegalArgumentException("unsupported address type");
781
782    InetSocketAddress tmp = (InetSocketAddress) address;
783    connect(tmp.getAddress(), tmp.getPort());
784  }
785
786  /**
787   * Returns the binding state of the socket.
788   *
789   * @return True if socket bound, false otherwise.
790   *
791   * @since 1.4
792   */
793  public boolean isBound()
794  {
795    return bound;
796  }
797
798  /**
799   * Returns the connection state of the socket.
800   *
801   * @return True if socket is connected, false otherwise.
802   *
803   * @since 1.4
804   */
805  public boolean isConnected()
806  {
807    return remoteAddress != null;
808  }
809
810  /**
811   * Returns the SocketAddress of the host this socket is conneted to
812   * or null if this socket is not connected.
813   *
814   * @return The socket address of the remote host if connected or null
815   *
816   * @since 1.4
817   */
818  public SocketAddress getRemoteSocketAddress()
819  {
820    if (! isConnected())
821      return null;
822
823    return new InetSocketAddress(remoteAddress, remotePort);
824  }
825
826  /**
827   * Returns the local SocketAddress this socket is bound to.
828   *
829   * @return The local SocketAddress or null if the socket is not bound.
830   *
831   * @since 1.4
832   */
833  public SocketAddress getLocalSocketAddress()
834  {
835    if (! isBound())
836      return null;
837
838    return new InetSocketAddress(getLocalAddress(), getLocalPort());
839  }
840
841  /**
842   * Enables/Disables SO_REUSEADDR.
843   *
844   * @param on Whether or not to have SO_REUSEADDR turned on.
845   *
846   * @exception SocketException If an error occurs.
847   *
848   * @since 1.4
849   */
850  public void setReuseAddress(boolean on) throws SocketException
851  {
852    if (isClosed())
853      throw new SocketException("socket is closed");
854
855    getImpl().setOption(SocketOptions.SO_REUSEADDR, Boolean.valueOf(on));
856  }
857
858  /**
859   * Checks if SO_REUSEADDR is enabled.
860   *
861   * @return True if SO_REUSEADDR is set on the socket, false otherwise.
862   *
863   * @exception SocketException If an error occurs.
864   *
865   * @since 1.4
866   */
867  public boolean getReuseAddress() throws SocketException
868  {
869    if (isClosed())
870      throw new SocketException("socket is closed");
871
872    Object buf = getImpl().getOption(SocketOptions.SO_REUSEADDR);
873
874    if (buf instanceof Boolean)
875      return ((Boolean) buf).booleanValue();
876
877    throw new SocketException("unexpected type");
878  }
879
880  /**
881   * Enables/Disables SO_BROADCAST
882   *
883   * @param enable True if SO_BROADCAST should be enabled, false otherwise.
884   *
885   * @exception SocketException If an error occurs
886   *
887   * @since 1.4
888   */
889  public void setBroadcast(boolean enable) throws SocketException
890  {
891    if (isClosed())
892      throw new SocketException("socket is closed");
893
894    getImpl().setOption(SocketOptions.SO_BROADCAST, Boolean.valueOf(enable));
895  }
896
897  /**
898   * Checks if SO_BROADCAST is enabled
899   *
900   * @return Whether SO_BROADCAST is set
901   *
902   * @exception SocketException If an error occurs
903   *
904   * @since 1.4
905   */
906  public boolean getBroadcast() throws SocketException
907  {
908    if (isClosed())
909      throw new SocketException("socket is closed");
910
911    Object buf = getImpl().getOption(SocketOptions.SO_BROADCAST);
912
913    if (buf instanceof Boolean)
914      return ((Boolean) buf).booleanValue();
915
916    throw new SocketException("unexpected type");
917  }
918
919  /**
920   * Sets the traffic class value
921   *
922   * @param tc The traffic class
923   *
924   * @exception SocketException If an error occurs
925   * @exception IllegalArgumentException If tc value is illegal
926   *
927   * @see DatagramSocket#getTrafficClass()
928   *
929   * @since 1.4
930   */
931  public void setTrafficClass(int tc) throws SocketException
932  {
933    if (isClosed())
934      throw new SocketException("socket is closed");
935
936    if (tc < 0 || tc > 255)
937      throw new IllegalArgumentException();
938
939    getImpl().setOption(SocketOptions.IP_TOS, Integer.valueOf(tc));
940  }
941
942  /**
943   * Returns the current traffic class
944   *
945   * @return The current traffic class.
946   *
947   * @see DatagramSocket#setTrafficClass(int tc)
948   *
949   * @exception SocketException If an error occurs
950   *
951   * @since 1.4
952   */
953  public int getTrafficClass() throws SocketException
954  {
955    if (isClosed())
956      throw new SocketException("socket is closed");
957
958    Object buf = getImpl().getOption(SocketOptions.IP_TOS);
959
960    if (buf instanceof Integer)
961      return ((Integer) buf).intValue();
962
963    throw new SocketException("unexpected type");
964  }
965
966  /**
967   * Sets the datagram socket implementation factory for the application
968   *
969   * @param fac The factory to set
970   *
971   * @exception IOException If an error occurs
972   * @exception SocketException If the factory is already defined
973   * @exception SecurityException If a security manager exists and its
974   * checkSetFactory method doesn't allow the operation
975   */
976  public static void setDatagramSocketImplFactory(DatagramSocketImplFactory fac)
977    throws IOException
978  {
979    if (factory != null)
980      throw new SocketException("DatagramSocketImplFactory already defined");
981
982    SecurityManager sm = System.getSecurityManager();
983    if (sm != null)
984      sm.checkSetFactory();
985
986    factory = fac;
987  }
988}