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 }