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      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}