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 }