Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: java/net/DatagramSocket.java


1   /* DatagramSocket.java -- A class to model UDP sockets
2      Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004, 2005
3      Free Software Foundation, Inc.
4   
5   This file is part of GNU Classpath.
6   
7   GNU Classpath is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 2, or (at your option)
10  any later version.
11  
12  GNU Classpath is distributed in the hope that it will be useful, but
13  WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  General Public License for more details.
16  
17  You should have received a copy of the GNU General Public License
18  along with GNU Classpath; see the file COPYING.  If not, write to the
19  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20  02110-1301 USA.
21  
22  Linking this library statically or dynamically with other modules is
23  making a combined work based on this library.  Thus, the terms and
24  conditions of the GNU General Public License cover the whole
25  combination.
26  
27  As a special exception, the copyright holders of this library give you
28  permission to link this library with independent modules to produce an
29  executable, regardless of the license terms of these independent
30  modules, and to copy and distribute the resulting executable under
31  terms of your choice, provided that you also meet, for each linked
32  independent module, the terms and conditions of the license of that
33  module.  An independent module is a module which is not derived from
34  or based on this library.  If you modify this library, you may extend
35  this exception to your version of the library, but you are not
36  obligated to do so.  If you do not wish to do so, delete this
37  exception statement from your version. */
38  
39  package java.net;
40  
41  import gnu.classpath.SystemProperties;
42  
43  import gnu.java.net.PlainDatagramSocketImpl;
44  import gnu.java.nio.DatagramChannelImpl;
45  
46  import java.io.IOException;
47  import java.nio.channels.DatagramChannel;
48  import java.nio.channels.IllegalBlockingModeException;
49  
50  
51  /**
52   * Written using on-line Java Platform 1.2 API Specification, as well
53   * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998).
54   * Status:  Believed complete and correct.
55   */
56  /**
57   * This class models a connectionless datagram socket that sends
58   * individual packets of data across the network.  In the TCP/IP world,
59   * this means UDP.  Datagram packets do not have guaranteed delivery,
60   * or any guarantee about the order the data will be received on the
61   * remote host.
62   *
63   * @author Aaron M. Renn (arenn@urbanophile.com)
64   * @author Warren Levy (warrenl@cygnus.com)
65   * @date May 3, 1999.
66   */
67  public class DatagramSocket
68  {
69    /**
70     * This is the user DatagramSocketImplFactory for this class.  If this
71     * variable is null, a default factory is used.
72     */
73    private static DatagramSocketImplFactory factory;
74  
75    /**
76     * This is the implementation object used by this socket.
77     */
78    private DatagramSocketImpl impl;
79  
80    /**
81     * True if socket implementation was created.
82     */
83    private boolean implCreated;
84  
85    /**
86     * This is the address we are "connected" to
87     */
88    private InetAddress remoteAddress;
89  
90    /**
91     * This is the port we are "connected" to
92     */
93    private int remotePort = -1;
94  
95    /**
96     * True if socket is bound.
97     */
98    private boolean bound;
99  
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       impl = new PlainDatagramSocketImpl();
180     else
181       try
182         {
183     impl =
184       (DatagramSocketImpl) Class.forName("java.net." + propVal
185                                          + "DatagramSocketImpl")
186                                 .newInstance();
187         }
188       catch (Exception e)
189         {
190     System.err.println("Could not instantiate class: java.net."
191                        + propVal + "DatagramSocketImpl");
192     impl = new PlainDatagramSocketImpl();
193         }
194 
195     if (address != null)
196       bind(address);
197   }
198 
199   // This needs to be accessible from java.net.MulticastSocket
200   DatagramSocketImpl getImpl() throws SocketException
201   {
202     try
203       {
204   if (! implCreated)
205     {
206       impl.create();
207       implCreated = true;
208     }
209 
210   return impl;
211       }
212     catch (IOException e)
213       {
214   SocketException se = new SocketException();
215   se.initCause(e);
216   throw se;
217       }
218   }
219 
220   /**
221    * Closes this datagram socket.
222    */
223   public void close()
224   {
225     if (isClosed())
226       return;
227 
228     try
229       {
230   getImpl().close();
231       }
232     catch (SocketException e)
233       {
234   // Ignore this case, just close the socket in finally clause.
235       }
236     finally
237       {
238   remoteAddress = null;
239   remotePort = -1;
240   impl = null;
241       }
242 
243     try
244       {
245   if (getChannel() != null)
246     getChannel().close();
247       }
248     catch (IOException e)
249       {
250   // Do nothing.
251       }
252   }
253 
254   /**
255    * This method returns the remote address to which this socket is
256    * connected.  If this socket is not connected, then this method will
257    * return <code>null</code>.
258    *
259    * @return The remote address.
260    *
261    * @since 1.2
262    */
263   public InetAddress getInetAddress()
264   {
265     return remoteAddress;
266   }
267 
268   /**
269    * This method returns the remote port to which this socket is
270    * connected.  If this socket is not connected, then this method will
271    * return -1.
272    *
273    * @return The remote port.
274    *
275    * @since 1.2
276    */
277   public int getPort()
278   {
279     return remotePort;
280   }
281 
282   /**
283    * Returns the local address this datagram socket is bound to.
284    *
285    * @return The local address is the socket is bound or null
286    *
287    * @since 1.1
288    */
289   public InetAddress getLocalAddress()
290   {
291     if (! isBound())
292       return null;
293 
294     InetAddress localAddr;
295 
296     try
297       {
298   localAddr =
299     (InetAddress) getImpl().getOption(SocketOptions.SO_BINDADDR);
300 
301   SecurityManager s = System.getSecurityManager();
302   if (s != null)
303     s.checkConnect(localAddr.getHostName(), -1);
304       }
305     catch (SecurityException e)
306       {
307   localAddr = InetAddress.ANY_IF;
308       }
309     catch (SocketException e)
310       {
311   // This cannot happen as we are bound.
312   return null;
313       }
314 
315     return localAddr;
316   }
317 
318   /**
319    * Returns the local port this socket is bound to.
320    *
321    * @return The local port number.
322    */
323   public int getLocalPort()
324   {
325     if (isClosed())
326       return -1;
327 
328     try
329       {
330   return getImpl().getLocalPort();
331       }
332     catch (SocketException e)
333       {
334   // This cannot happen as we are bound.
335   return 0;
336       }
337   }
338 
339   /**
340    * Returns the value of the socket's SO_TIMEOUT setting.  If this method
341    * returns 0 then SO_TIMEOUT is disabled.
342    *
343    * @return The current timeout in milliseconds.
344    *
345    * @exception SocketException If an error occurs.
346    *
347    * @since 1.1
348    */
349   public synchronized int getSoTimeout() throws SocketException
350   {
351     if (isClosed())
352       throw new SocketException("socket is closed");
353 
354     Object buf = getImpl().getOption(SocketOptions.SO_TIMEOUT);
355 
356     if (buf instanceof Integer)
357       return ((Integer) buf).intValue();
358 
359     throw new SocketException("unexpected type");
360   }
361 
362   /**
363    * Sets the value of the socket's SO_TIMEOUT value.  A value of 0 will
364    * disable SO_TIMEOUT.  Any other value is the number of milliseconds
365    * a socket read/write will block before timing out.
366    *
367    * @param timeout The new SO_TIMEOUT value in milliseconds.
368    *
369    * @exception SocketException If an error occurs.
370    *
371    * @since 1.1
372    */
373   public synchronized void setSoTimeout(int timeout) throws SocketException
374   {
375     if (isClosed())
376       throw new SocketException("socket is closed");
377 
378     if (timeout < 0)
379       throw new IllegalArgumentException("Invalid timeout: " + timeout);
380 
381     getImpl().setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout));
382   }
383 
384   /**
385    * This method returns the value of the system level socket option
386    * SO_SNDBUF, which is used by the operating system to tune buffer
387    * sizes for data transfers.
388    *
389    * @return The send buffer size.
390    *
391    * @exception SocketException If an error occurs.
392    *
393    * @since 1.2
394    */
395   public int getSendBufferSize() throws SocketException
396   {
397     if (isClosed())
398       throw new SocketException("socket is closed");
399 
400     Object buf = getImpl().getOption(SocketOptions.SO_SNDBUF);
401 
402     if (buf instanceof Integer)
403       return ((Integer) buf).intValue();
404 
405     throw new SocketException("unexpected type");
406   }
407 
408   /**
409    * This method sets the value for the system level socket option
410    * SO_SNDBUF to the specified value.  Note that valid values for this
411    * option are specific to a given operating system.
412    *
413    * @param size The new send buffer size.
414    *
415    * @exception SocketException If an error occurs.
416    * @exception IllegalArgumentException If size is 0 or negative.
417    *
418    * @since 1.2
419    */
420   public void setSendBufferSize(int size) throws SocketException
421   {
422     if (isClosed())
423       throw new SocketException("socket is closed");
424 
425     if (size < 0)
426       throw new IllegalArgumentException("Buffer size is less than 0");
427 
428     getImpl().setOption(SocketOptions.SO_SNDBUF, new Integer(size));
429   }
430 
431   /**
432    * This method returns the value of the system level socket option
433    * SO_RCVBUF, which is used by the operating system to tune buffer
434    * sizes for data transfers.
435    *
436    * @return The receive buffer size.
437    *
438    * @exception SocketException If an error occurs.
439    *
440    * @since 1.2
441    */
442   public int getReceiveBufferSize() throws SocketException
443   {
444     if (isClosed())
445       throw new SocketException("socket is closed");
446 
447     Object buf = getImpl().getOption(SocketOptions.SO_RCVBUF);
448 
449     if (buf instanceof Integer)
450       return ((Integer) buf).intValue();
451 
452     throw new SocketException("unexpected type");
453   }
454 
455   /**
456    * This method sets the value for the system level socket option
457    * SO_RCVBUF to the specified value.  Note that valid values for this
458    * option are specific to a given operating system.
459    *
460    * @param size The new receive buffer size.
461    *
462    * @exception SocketException If an error occurs.
463    * @exception IllegalArgumentException If size is 0 or negative.
464    *
465    * @since 1.2
466    */
467   public void setReceiveBufferSize(int size) throws SocketException
468   {
469     if (isClosed())
470       throw new SocketException("socket is closed");
471 
472     if (size < 0)
473       throw new IllegalArgumentException("Buffer size is less than 0");
474 
475     getImpl().setOption(SocketOptions.SO_RCVBUF, new Integer(size));
476   }
477 
478   /**
479    * This method connects this socket to the specified address and port.
480    * When a datagram socket is connected, it will only send or receive
481    * packets to and from the host to which it is connected. A multicast
482    * socket that is connected may only send and not receive packets.
483    *
484    * @param address The address to connect this socket to.
485    * @param port The port to connect this socket to.
486    *
487    * @exception SocketException If an error occurs.
488    * @exception IllegalArgumentException If address or port are invalid.
489    * @exception SecurityException If the caller is not allowed to send
490    * datagrams to or receive from this address and port.
491    *
492    * @since 1.2
493    */
494   public void connect(InetAddress address, int port)
495   {
496     if (address == null)
497       throw new IllegalArgumentException("Connect address may not be null");
498 
499     if ((port < 1) || (port > 65535))
500       throw new IllegalArgumentException("Port number is illegal: " + port);
501 
502     SecurityManager sm = System.getSecurityManager();
503     if (sm != null)
504       sm.checkConnect(address.getHostName(), port);
505 
506     try
507       {
508   getImpl().connect(address, port);
509   remoteAddress = address;
510   remotePort = port;
511       }
512     catch (SocketException e)
513       {
514   // This means simply not connected or connect not implemented.
515       }
516   }
517 
518   /**
519    * This method disconnects this socket from the address/port it was
520    * connected to.  If the socket was not connected in the first place,
521    * this method does nothing.
522    *
523    * @since 1.2
524    */
525   public void disconnect()
526   {
527     if (! isConnected())
528       return;
529 
530     try
531       {
532   getImpl().disconnect();
533       }
534     catch (SocketException e)
535       {
536   // This cannot happen as we are connected.
537       }
538     finally
539       {
540   remoteAddress = null;
541   remotePort = -1;
542       }
543   }
544 
545   /**
546    * Reads a datagram packet from the socket.  Note that this method
547    * will block until a packet is received from the network.  On return,
548    * the passed in <code>DatagramPacket</code> is populated with the data
549    * received and all the other information about the packet.
550    *
551    * @param p A <code>DatagramPacket</code> for storing the data
552    *
553    * @exception IOException If an error occurs.
554    * @exception SocketTimeoutException If setSoTimeout was previously called
555    * and the timeout has expired.
556    * @exception PortUnreachableException If the socket is connected to a
557    * currently unreachable destination. Note, there is no guarantee that the
558    * exception will be thrown.
559    * @exception IllegalBlockingModeException If this socket has an associated
560    * channel, and the channel is in non-blocking mode.
561    * @exception SecurityException If a security manager exists and its
562    * checkAccept method doesn't allow the receive.
563    */
564   public synchronized void receive(DatagramPacket p) throws IOException
565   {
566     if (isClosed())
567       throw new SocketException("socket is closed");
568 
569     if (remoteAddress != null && remoteAddress.isMulticastAddress())
570       throw new IOException
571   ("Socket connected to a multicast address my not receive");
572 
573     if (getChannel() != null && ! getChannel().isBlocking()
574         && ! ((DatagramChannelImpl) getChannel()).isInChannelOperation())
575       throw new IllegalBlockingModeException();
576 
577     getImpl().receive(p);
578 
579     SecurityManager s = System.getSecurityManager();
580     if (s != null && isConnected())
581       s.checkAccept(p.getAddress().getHostName(), p.getPort());
582   }
583 
584   /**
585    * Sends the specified packet.  The host and port to which the packet
586    * are to be sent should be set inside the packet.
587    *
588    * @param p The datagram packet to send.
589    *
590    * @exception IOException If an error occurs.
591    * @exception SecurityException If a security manager exists and its
592    * checkMulticast or checkConnect method doesn't allow the send.
593    * @exception PortUnreachableException If the socket is connected to a
594    * currently unreachable destination. Note, there is no guarantee that the
595    * exception will be thrown.
596    * @exception IllegalBlockingModeException If this socket has an associated
597    * channel, and the channel is in non-blocking mode.
598    */
599   public void send(DatagramPacket p) throws IOException
600   {
601     if (isClosed())
602       throw new SocketException("socket is closed");
603 
604     // JDK1.2: Don't do security checks if socket is connected; see jdk1.2 api.
605     SecurityManager s = System.getSecurityManager();
606     if (s != null && ! isConnected())
607       {
608   InetAddress addr = p.getAddress();
609   if (addr.isMulticastAddress())
610     s.checkMulticast(addr);
611   else
612     s.checkConnect(addr.getHostAddress(), p.getPort());
613       }
614 
615     if (isConnected())
616       {
617   if (p.getAddress() != null
618       && (remoteAddress != p.getAddress() || remotePort != p.getPort()))
619     throw new IllegalArgumentException
620       ("DatagramPacket address does not match remote address");
621       }
622 
623     // FIXME: if this is a subclass of MulticastSocket,
624     // use getTimeToLive for TTL val.
625     if (getChannel() != null && ! getChannel().isBlocking()
626         && ! ((DatagramChannelImpl) getChannel()).isInChannelOperation())
627       throw new IllegalBlockingModeException();
628 
629     getImpl().send(p);
630   }
631 
632   /**
633    * Binds the socket to the given socket address.
634    *
635    * @param address The socket address to bind to.
636    *
637    * @exception SocketException If an error occurs.
638    * @exception SecurityException If a security manager exists and
639    * its checkListen method doesn't allow the operation.
640    * @exception IllegalArgumentException If address type is not supported.
641    *
642    * @since 1.4
643    */
644   public void bind(SocketAddress address) throws SocketException
645   {
646     if (isClosed())
647       throw new SocketException("socket is closed");
648 
649     if (! (address instanceof InetSocketAddress))
650       throw new IllegalArgumentException("unsupported address type");
651 
652     InetAddress addr = ((InetSocketAddress) address).getAddress();
653     int port = ((InetSocketAddress) address).getPort();
654 
655     if (port < 0 || port > 65535)
656       throw new IllegalArgumentException("Invalid port: " + port);
657 
658     SecurityManager s = System.getSecurityManager();
659     if (s != null)
660       s.checkListen(port);
661 
662     if (addr == null)
663       addr = InetAddress.ANY_IF;
664 
665     try
666       {
667   getImpl().bind(port, addr);
668   bound = true;
669       }
670     catch (SocketException exception)
671       {
672   getImpl().close();
673   throw exception;
674       }
675     catch (RuntimeException exception)
676       {
677   getImpl().close();
678   throw exception;
679       }
680     catch (Error error)
681       {
682   getImpl().close();
683   throw error;
684       }
685   }
686 
687   /**
688    * Checks if the datagram socket is closed.
689    *
690    * @return True if socket is closed, false otherwise.
691    *
692    * @since 1.4
693    */
694   public boolean isClosed()
695   {
696     return impl == null;
697   }
698 
699   /**
700    * Returns the datagram channel assoziated with this datagram socket.
701    *
702    * @return The associated <code>DatagramChannel</code> object or null
703    *
704    * @since 1.4
705    */
706   public DatagramChannel getChannel()
707   {
708     return null;
709   }
710 
711   /**
712    * Connects the datagram socket to a specified socket address.
713    *
714    * @param address The socket address to connect to.
715    *
716    * @exception SocketException If an error occurs.
717    * @exception IllegalArgumentException If address type is not supported.
718    *
719    * @since 1.4
720    */
721   public void connect(SocketAddress address) throws SocketException
722   {
723     if (isClosed())
724       throw new SocketException("socket is closed");
725 
726     if (! (address instanceof InetSocketAddress))
727       throw new IllegalArgumentException("unsupported address type");
728 
729     InetSocketAddress tmp = (InetSocketAddress) address;
730     connect(tmp.getAddress(), tmp.getPort());
731   }
732 
733   /**
734    * Returns the binding state of the socket.
735    *
736    * @return True if socket bound, false otherwise.
737    *
738    * @since 1.4
739    */
740   public boolean isBound()
741   {
742     return bound;
743   }
744 
745   /**
746    * Returns the connection state of the socket.
747    *
748    * @return True if socket is connected, false otherwise.
749    *
750    * @since 1.4
751    */
752   public boolean isConnected()
753   {
754     return remoteAddress != null;
755   }
756 
757   /**
758    * Returns the SocketAddress of the host this socket is conneted to
759    * or null if this socket is not connected.
760    *
761    * @return The socket address of the remote host if connected or null
762    *
763    * @since 1.4
764    */
765   public SocketAddress getRemoteSocketAddress()
766   {
767     if (! isConnected())
768       return null;
769 
770     return new InetSocketAddress(remoteAddress, remotePort);
771   }
772 
773   /**
774    * Returns the local SocketAddress this socket is bound to.
775    *
776    * @return The local SocketAddress or null if the socket is not bound.
777    *
778    * @since 1.4
779    */
780   public SocketAddress getLocalSocketAddress()
781   {
782     if (! isBound())
783       return null;
784 
785     return new InetSocketAddress(getLocalAddress(), getLocalPort());
786   }
787 
788   /**
789    * Enables/Disables SO_REUSEADDR.
790    *
791    * @param on Whether or not to have SO_REUSEADDR turned on.
792    *
793    * @exception SocketException If an error occurs.
794    *
795    * @since 1.4
796    */
797   public void setReuseAddress(boolean on) throws SocketException
798   {
799     if (isClosed())
800       throw new SocketException("socket is closed");
801 
802     getImpl().setOption(SocketOptions.SO_REUSEADDR, Boolean.valueOf(on));
803   }
804 
805   /**
806    * Checks if SO_REUSEADDR is enabled.
807    *
808    * @return True if SO_REUSEADDR is set on the socket, false otherwise.
809    *
810    * @exception SocketException If an error occurs.
811    *
812    * @since 1.4
813    */
814   public boolean getReuseAddress() throws SocketException
815   {
816     if (isClosed())
817       throw new SocketException("socket is closed");
818 
819     Object buf = getImpl().getOption(SocketOptions.SO_REUSEADDR);
820 
821     if (buf instanceof Boolean)
822       return ((Boolean) buf).booleanValue();
823 
824     throw new SocketException("unexpected type");
825   }
826 
827   /**
828    * Enables/Disables SO_BROADCAST
829    *
830    * @param enable True if SO_BROADCAST should be enabled, false otherwise.
831    *
832    * @exception SocketException If an error occurs
833    *
834    * @since 1.4
835    */
836   public void setBroadcast(boolean enable) throws SocketException
837   {
838     if (isClosed())
839       throw new SocketException("socket is closed");
840 
841     getImpl().setOption(SocketOptions.SO_BROADCAST, Boolean.valueOf(enable));
842   }
843 
844   /**
845    * Checks if SO_BROADCAST is enabled
846    *
847    * @return Whether SO_BROADCAST is set
848    *
849    * @exception SocketException If an error occurs
850    *
851    * @since 1.4
852    */
853   public boolean getBroadcast() throws SocketException
854   {
855     if (isClosed())
856       throw new SocketException("socket is closed");
857 
858     Object buf = getImpl().getOption(SocketOptions.SO_BROADCAST);
859 
860     if (buf instanceof Boolean)
861       return ((Boolean) buf).booleanValue();
862 
863     throw new SocketException("unexpected type");
864   }
865 
866   /**
867    * Sets the traffic class value
868    *
869    * @param tc The traffic class
870    *
871    * @exception SocketException If an error occurs
872    * @exception IllegalArgumentException If tc value is illegal
873    *
874    * @see DatagramSocket#getTrafficClass()
875    *
876    * @since 1.4
877    */
878   public void setTrafficClass(int tc) throws SocketException
879   {
880     if (isClosed())
881       throw new SocketException("socket is closed");
882 
883     if (tc < 0 || tc > 255)
884       throw new IllegalArgumentException();
885 
886     getImpl().setOption(SocketOptions.IP_TOS, new Integer(tc));
887   }
888 
889   /**
890    * Returns the current traffic class
891    *
892    * @return The current traffic class.
893    *
894    * @see DatagramSocket#setTrafficClass(int tc)
895    *
896    * @exception SocketException If an error occurs
897    *
898    * @since 1.4
899    */
900   public int getTrafficClass() throws SocketException
901   {
902     if (isClosed())
903       throw new SocketException("socket is closed");
904 
905     Object buf = getImpl().getOption(SocketOptions.IP_TOS);
906 
907     if (buf instanceof Integer)
908       return ((Integer) buf).intValue();
909 
910     throw new SocketException("unexpected type");
911   }
912 
913   /**
914    * Sets the datagram socket implementation factory for the application
915    *
916    * @param fac The factory to set
917    *
918    * @exception IOException If an error occurs
919    * @exception SocketException If the factory is already defined
920    * @exception SecurityException If a security manager exists and its
921    * checkSetFactory method doesn't allow the operation
922    */
923   public static void setDatagramSocketImplFactory(DatagramSocketImplFactory fac)
924     throws IOException
925   {
926     if (factory != null)
927       throw new SocketException("DatagramSocketImplFactory already defined");
928 
929     SecurityManager sm = System.getSecurityManager();
930     if (sm != null)
931       sm.checkSetFactory();
932 
933     factory = fac;
934   }
935 }