1 /* DatagramSocket.java -- A class to model UDP sockets
2 Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004, 2005
3 Free Software Foundation, Inc.
5 This file is part of GNU Classpath.
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)
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.
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
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
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. */
41 import gnu
.classpath
.SystemProperties
;
43 import gnu
.java
.net
.PlainDatagramSocketImpl
;
44 import gnu
.java
.nio
.DatagramChannelImpl
;
46 import java
.io
.IOException
;
47 import java
.nio
.channels
.DatagramChannel
;
48 import java
.nio
.channels
.IllegalBlockingModeException
;
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.
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
63 * @author Aaron M. Renn (arenn@urbanophile.com)
64 * @author Warren Levy (warrenl@cygnus.com)
67 public class DatagramSocket
70 * This is the user DatagramSocketImplFactory for this class. If this
71 * variable is null, a default factory is used.
73 private static DatagramSocketImplFactory factory
;
76 * This is the implementation object used by this socket.
78 private DatagramSocketImpl impl
;
81 * True if socket implementation was created.
83 private boolean implCreated
;
86 * This is the address we are "connected" to
88 private InetAddress remoteAddress
;
91 * This is the port we are "connected" to
93 private int remotePort
= -1;
96 * True if socket is bound.
98 private boolean bound
;
101 * Creates a <code>DatagramSocket</code> from a specified
102 * <code>DatagramSocketImpl</code> instance
104 * @param impl The <code>DatagramSocketImpl</code> the socket will be
109 protected DatagramSocket(DatagramSocketImpl impl
)
112 throw new NullPointerException("impl may not be null");
115 this.remoteAddress
= null;
116 this.remotePort
= -1;
120 * Initializes a new instance of <code>DatagramSocket</code> that binds to
121 * a random port and every address on the local machine.
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.
127 public DatagramSocket() throws SocketException
129 this(new InetSocketAddress(0));
133 * Initializes a new instance of <code>DatagramSocket</code> that binds to
134 * the specified port and every address on the local machine.
136 * @param port The local port number to bind to.
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.
142 public DatagramSocket(int port
) throws SocketException
144 this(new InetSocketAddress(port
));
148 * Initializes a new instance of <code>DatagramSocket</code> that binds to
149 * the specified local port and address.
151 * @param port The local port number to bind to.
152 * @param addr The local address to bind to.
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.
158 public DatagramSocket(int port
, InetAddress addr
) throws SocketException
160 this(new InetSocketAddress(addr
, port
));
164 * Initializes a new instance of <code>DatagramSocket</code> that binds to
165 * the specified local port and address.
167 * @param address The local address and port number to bind to.
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.
175 public DatagramSocket(SocketAddress address
) throws SocketException
177 String propVal
= SystemProperties
.getProperty("impl.prefix");
178 if (propVal
== null || propVal
.equals(""))
181 impl
= factory
.createDatagramSocketImpl();
183 impl
= new PlainDatagramSocketImpl();
189 (DatagramSocketImpl
) Class
.forName("java.net." + propVal
190 + "DatagramSocketImpl")
195 System
.err
.println("Could not instantiate class: java.net."
196 + propVal
+ "DatagramSocketImpl");
197 impl
= new PlainDatagramSocketImpl();
204 // This needs to be accessible from java.net.MulticastSocket
205 DatagramSocketImpl
getImpl() throws SocketException
217 catch (IOException e
)
219 SocketException se
= new SocketException();
226 * Closes this datagram socket.
237 catch (SocketException e
)
239 // Ignore this case, just close the socket in finally clause.
243 remoteAddress
= null;
250 if (getChannel() != null)
251 getChannel().close();
253 catch (IOException e
)
260 * This method returns the remote address to which this socket is
261 * connected. If this socket is not connected, then this method will
262 * return <code>null</code>.
264 * @return The remote address.
268 public InetAddress
getInetAddress()
270 return remoteAddress
;
274 * This method returns the remote port to which this socket is
275 * connected. If this socket is not connected, then this method will
278 * @return The remote port.
288 * Returns the local address this datagram socket is bound to.
290 * @return The local address is the socket is bound or null
294 public InetAddress
getLocalAddress()
299 InetAddress localAddr
;
304 (InetAddress
) getImpl().getOption(SocketOptions
.SO_BINDADDR
);
306 SecurityManager s
= System
.getSecurityManager();
308 s
.checkConnect(localAddr
.getHostName(), -1);
310 catch (SecurityException e
)
312 localAddr
= InetAddress
.ANY_IF
;
314 catch (SocketException e
)
316 // This cannot happen as we are bound.
324 * Returns the local port this socket is bound to.
326 * @return The local port number.
328 public int getLocalPort()
335 return getImpl().getLocalPort();
337 catch (SocketException e
)
339 // This cannot happen as we are bound.
345 * Returns the value of the socket's SO_TIMEOUT setting. If this method
346 * returns 0 then SO_TIMEOUT is disabled.
348 * @return The current timeout in milliseconds.
350 * @exception SocketException If an error occurs.
354 public synchronized int getSoTimeout() throws SocketException
357 throw new SocketException("socket is closed");
359 Object buf
= getImpl().getOption(SocketOptions
.SO_TIMEOUT
);
361 if (buf
instanceof Integer
)
362 return ((Integer
) buf
).intValue();
364 throw new SocketException("unexpected type");
368 * Sets the value of the socket's SO_TIMEOUT value. A value of 0 will
369 * disable SO_TIMEOUT. Any other value is the number of milliseconds
370 * a socket read/write will block before timing out.
372 * @param timeout The new SO_TIMEOUT value in milliseconds.
374 * @exception SocketException If an error occurs.
378 public synchronized void setSoTimeout(int timeout
) throws SocketException
381 throw new SocketException("socket is closed");
384 throw new IllegalArgumentException("Invalid timeout: " + timeout
);
386 getImpl().setOption(SocketOptions
.SO_TIMEOUT
, new Integer(timeout
));
390 * This method returns the value of the system level socket option
391 * SO_SNDBUF, which is used by the operating system to tune buffer
392 * sizes for data transfers.
394 * @return The send buffer size.
396 * @exception SocketException If an error occurs.
400 public int getSendBufferSize() throws SocketException
403 throw new SocketException("socket is closed");
405 Object buf
= getImpl().getOption(SocketOptions
.SO_SNDBUF
);
407 if (buf
instanceof Integer
)
408 return ((Integer
) buf
).intValue();
410 throw new SocketException("unexpected type");
414 * This method sets the value for the system level socket option
415 * SO_SNDBUF to the specified value. Note that valid values for this
416 * option are specific to a given operating system.
418 * @param size The new send buffer size.
420 * @exception SocketException If an error occurs.
421 * @exception IllegalArgumentException If size is 0 or negative.
425 public void setSendBufferSize(int size
) throws SocketException
428 throw new SocketException("socket is closed");
431 throw new IllegalArgumentException("Buffer size is less than 0");
433 getImpl().setOption(SocketOptions
.SO_SNDBUF
, new Integer(size
));
437 * This method returns the value of the system level socket option
438 * SO_RCVBUF, which is used by the operating system to tune buffer
439 * sizes for data transfers.
441 * @return The receive buffer size.
443 * @exception SocketException If an error occurs.
447 public int getReceiveBufferSize() throws SocketException
450 throw new SocketException("socket is closed");
452 Object buf
= getImpl().getOption(SocketOptions
.SO_RCVBUF
);
454 if (buf
instanceof Integer
)
455 return ((Integer
) buf
).intValue();
457 throw new SocketException("unexpected type");
461 * This method sets the value for the system level socket option
462 * SO_RCVBUF to the specified value. Note that valid values for this
463 * option are specific to a given operating system.
465 * @param size The new receive buffer size.
467 * @exception SocketException If an error occurs.
468 * @exception IllegalArgumentException If size is 0 or negative.
472 public void setReceiveBufferSize(int size
) throws SocketException
475 throw new SocketException("socket is closed");
478 throw new IllegalArgumentException("Buffer size is less than 0");
480 getImpl().setOption(SocketOptions
.SO_RCVBUF
, new Integer(size
));
484 * This method connects this socket to the specified address and port.
485 * When a datagram socket is connected, it will only send or receive
486 * packets to and from the host to which it is connected. A multicast
487 * socket that is connected may only send and not receive packets.
489 * @param address The address to connect this socket to.
490 * @param port The port to connect this socket to.
492 * @exception IllegalArgumentException If address or port are invalid.
493 * @exception SecurityException If the caller is not allowed to send
494 * datagrams to or receive from this address and port.
498 public void connect(InetAddress address
, int port
)
501 throw new IllegalArgumentException("Connect address may not be null");
503 if ((port
< 1) || (port
> 65535))
504 throw new IllegalArgumentException("Port number is illegal: " + port
);
506 SecurityManager sm
= System
.getSecurityManager();
508 sm
.checkConnect(address
.getHostName(), port
);
512 getImpl().connect(address
, port
);
513 remoteAddress
= address
;
516 catch (SocketException e
)
518 // This means simply not connected or connect not implemented.
523 * This method disconnects this socket from the address/port it was
524 * connected to. If the socket was not connected in the first place,
525 * this method does nothing.
529 public void disconnect()
536 getImpl().disconnect();
538 catch (SocketException e
)
540 // This cannot happen as we are connected.
544 remoteAddress
= null;
550 * Reads a datagram packet from the socket. Note that this method
551 * will block until a packet is received from the network. On return,
552 * the passed in <code>DatagramPacket</code> is populated with the data
553 * received and all the other information about the packet.
555 * @param p A <code>DatagramPacket</code> for storing the data
557 * @exception IOException If an error occurs.
558 * @exception SocketTimeoutException If setSoTimeout was previously called
559 * and the timeout has expired.
560 * @exception PortUnreachableException If the socket is connected to a
561 * currently unreachable destination. Note, there is no guarantee that the
562 * exception will be thrown.
563 * @exception IllegalBlockingModeException If this socket has an associated
564 * channel, and the channel is in non-blocking mode.
565 * @exception SecurityException If a security manager exists and its
566 * checkAccept method doesn't allow the receive.
568 public synchronized void receive(DatagramPacket p
) throws IOException
571 throw new SocketException("socket is closed");
573 if (remoteAddress
!= null && remoteAddress
.isMulticastAddress())
574 throw new IOException
575 ("Socket connected to a multicast address my not receive");
577 if (getChannel() != null && ! getChannel().isBlocking()
578 && ! ((DatagramChannelImpl
) getChannel()).isInChannelOperation())
579 throw new IllegalBlockingModeException();
581 getImpl().receive(p
);
583 SecurityManager s
= System
.getSecurityManager();
584 if (s
!= null && isConnected())
585 s
.checkAccept(p
.getAddress().getHostName(), p
.getPort());
589 * Sends the specified packet. The host and port to which the packet
590 * are to be sent should be set inside the packet.
592 * @param p The datagram packet to send.
594 * @exception IOException If an error occurs.
595 * @exception SecurityException If a security manager exists and its
596 * checkMulticast or checkConnect method doesn't allow the send.
597 * @exception PortUnreachableException If the socket is connected to a
598 * currently unreachable destination. Note, there is no guarantee that the
599 * exception will be thrown.
600 * @exception IllegalBlockingModeException If this socket has an associated
601 * channel, and the channel is in non-blocking mode.
603 public void send(DatagramPacket p
) throws IOException
606 throw new SocketException("socket is closed");
608 // JDK1.2: Don't do security checks if socket is connected; see jdk1.2 api.
609 SecurityManager s
= System
.getSecurityManager();
610 if (s
!= null && ! isConnected())
612 InetAddress addr
= p
.getAddress();
613 if (addr
.isMulticastAddress())
614 s
.checkMulticast(addr
);
616 s
.checkConnect(addr
.getHostAddress(), p
.getPort());
621 if (p
.getAddress() != null
622 && (remoteAddress
!= p
.getAddress() || remotePort
!= p
.getPort()))
623 throw new IllegalArgumentException
624 ("DatagramPacket address does not match remote address");
627 // FIXME: if this is a subclass of MulticastSocket,
628 // use getTimeToLive for TTL val.
629 if (getChannel() != null && ! getChannel().isBlocking()
630 && ! ((DatagramChannelImpl
) getChannel()).isInChannelOperation())
631 throw new IllegalBlockingModeException();
637 * Binds the socket to the given socket address.
639 * @param address The socket address to bind to.
641 * @exception SocketException If an error occurs.
642 * @exception SecurityException If a security manager exists and
643 * its checkListen method doesn't allow the operation.
644 * @exception IllegalArgumentException If address type is not supported.
648 public void bind(SocketAddress address
) throws SocketException
651 throw new SocketException("socket is closed");
653 if (! (address
instanceof InetSocketAddress
))
654 throw new IllegalArgumentException("unsupported address type");
656 InetAddress addr
= ((InetSocketAddress
) address
).getAddress();
657 int port
= ((InetSocketAddress
) address
).getPort();
659 if (port
< 0 || port
> 65535)
660 throw new IllegalArgumentException("Invalid port: " + port
);
662 SecurityManager s
= System
.getSecurityManager();
667 addr
= InetAddress
.ANY_IF
;
671 getImpl().bind(port
, addr
);
674 catch (SocketException exception
)
679 catch (RuntimeException exception
)
692 * Checks if the datagram socket is closed.
694 * @return True if socket is closed, false otherwise.
698 public boolean isClosed()
704 * Returns the datagram channel assoziated with this datagram socket.
706 * @return The associated <code>DatagramChannel</code> object or null
710 public DatagramChannel
getChannel()
716 * Connects the datagram socket to a specified socket address.
718 * @param address The socket address to connect to.
720 * @exception SocketException If an error occurs.
721 * @exception IllegalArgumentException If address type is not supported.
725 public void connect(SocketAddress address
) throws SocketException
728 throw new SocketException("socket is closed");
730 if (! (address
instanceof InetSocketAddress
))
731 throw new IllegalArgumentException("unsupported address type");
733 InetSocketAddress tmp
= (InetSocketAddress
) address
;
734 connect(tmp
.getAddress(), tmp
.getPort());
738 * Returns the binding state of the socket.
740 * @return True if socket bound, false otherwise.
744 public boolean isBound()
750 * Returns the connection state of the socket.
752 * @return True if socket is connected, false otherwise.
756 public boolean isConnected()
758 return remoteAddress
!= null;
762 * Returns the SocketAddress of the host this socket is conneted to
763 * or null if this socket is not connected.
765 * @return The socket address of the remote host if connected or null
769 public SocketAddress
getRemoteSocketAddress()
774 return new InetSocketAddress(remoteAddress
, remotePort
);
778 * Returns the local SocketAddress this socket is bound to.
780 * @return The local SocketAddress or null if the socket is not bound.
784 public SocketAddress
getLocalSocketAddress()
789 return new InetSocketAddress(getLocalAddress(), getLocalPort());
793 * Enables/Disables SO_REUSEADDR.
795 * @param on Whether or not to have SO_REUSEADDR turned on.
797 * @exception SocketException If an error occurs.
801 public void setReuseAddress(boolean on
) throws SocketException
804 throw new SocketException("socket is closed");
806 getImpl().setOption(SocketOptions
.SO_REUSEADDR
, Boolean
.valueOf(on
));
810 * Checks if SO_REUSEADDR is enabled.
812 * @return True if SO_REUSEADDR is set on the socket, false otherwise.
814 * @exception SocketException If an error occurs.
818 public boolean getReuseAddress() throws SocketException
821 throw new SocketException("socket is closed");
823 Object buf
= getImpl().getOption(SocketOptions
.SO_REUSEADDR
);
825 if (buf
instanceof Boolean
)
826 return ((Boolean
) buf
).booleanValue();
828 throw new SocketException("unexpected type");
832 * Enables/Disables SO_BROADCAST
834 * @param enable True if SO_BROADCAST should be enabled, false otherwise.
836 * @exception SocketException If an error occurs
840 public void setBroadcast(boolean enable
) throws SocketException
843 throw new SocketException("socket is closed");
845 getImpl().setOption(SocketOptions
.SO_BROADCAST
, Boolean
.valueOf(enable
));
849 * Checks if SO_BROADCAST is enabled
851 * @return Whether SO_BROADCAST is set
853 * @exception SocketException If an error occurs
857 public boolean getBroadcast() throws SocketException
860 throw new SocketException("socket is closed");
862 Object buf
= getImpl().getOption(SocketOptions
.SO_BROADCAST
);
864 if (buf
instanceof Boolean
)
865 return ((Boolean
) buf
).booleanValue();
867 throw new SocketException("unexpected type");
871 * Sets the traffic class value
873 * @param tc The traffic class
875 * @exception SocketException If an error occurs
876 * @exception IllegalArgumentException If tc value is illegal
878 * @see DatagramSocket#getTrafficClass()
882 public void setTrafficClass(int tc
) throws SocketException
885 throw new SocketException("socket is closed");
887 if (tc
< 0 || tc
> 255)
888 throw new IllegalArgumentException();
890 getImpl().setOption(SocketOptions
.IP_TOS
, new Integer(tc
));
894 * Returns the current traffic class
896 * @return The current traffic class.
898 * @see DatagramSocket#setTrafficClass(int tc)
900 * @exception SocketException If an error occurs
904 public int getTrafficClass() throws SocketException
907 throw new SocketException("socket is closed");
909 Object buf
= getImpl().getOption(SocketOptions
.IP_TOS
);
911 if (buf
instanceof Integer
)
912 return ((Integer
) buf
).intValue();
914 throw new SocketException("unexpected type");
918 * Sets the datagram socket implementation factory for the application
920 * @param fac The factory to set
922 * @exception IOException If an error occurs
923 * @exception SocketException If the factory is already defined
924 * @exception SecurityException If a security manager exists and its
925 * checkSetFactory method doesn't allow the operation
927 public static void setDatagramSocketImplFactory(DatagramSocketImplFactory fac
)
931 throw new SocketException("DatagramSocketImplFactory already defined");
933 SecurityManager sm
= System
.getSecurityManager();
935 sm
.checkSetFactory();