6621689: (dc spec) DatagramChannel.receive when channel is not bound is not specified
Reviewed-by: sherman
--- a/jdk/src/share/classes/java/nio/channels/DatagramChannel.java Tue Mar 24 14:08:37 2009 +0000
+++ b/jdk/src/share/classes/java/nio/channels/DatagramChannel.java Tue Mar 24 14:10:38 2009 +0000
@@ -261,7 +261,10 @@
*
* <p> This method may be invoked at any time. It will not have any effect
* on read or write operations that are already in progress at the moment
- * that it is invoked. </p>
+ * that it is invoked. If this channel's socket is not bound then this method
+ * will first cause the socket to be bound to an address that is assigned
+ * automatically, as if invoking the {@link #bind bind} method with a
+ * parameter of {@code null}. </p>
*
* @param remote
* The remote address to which this channel is to be connected
@@ -356,7 +359,10 @@
* <p> This method may be invoked at any time. If another thread has
* already initiated a read operation upon this channel, however, then an
* invocation of this method will block until the first operation is
- * complete. </p>
+ * complete. If this channel's socket is not bound then this method will
+ * first cause the socket to be bound to an address that is assigned
+ * automatically, as if invoking the {@link #bind bind} method with a
+ * parameter of {@code null}. </p>
*
* @param dst
* The buffer into which the datagram is to be transferred
@@ -413,7 +419,10 @@
* <p> This method may be invoked at any time. If another thread has
* already initiated a write operation upon this channel, however, then an
* invocation of this method will block until the first operation is
- * complete. </p>
+ * complete. If this channel's socket is not bound then this method will
+ * first cause the socket to be bound to an address that is assigned
+ * automatically, as if by invoking the {@link #bind bind) method with a
+ * parameter of {@code null}. </p>
*
* @param src
* The buffer containing the datagram to be sent
--- a/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java Tue Mar 24 14:08:37 2009 +0000
+++ b/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java Tue Mar 24 14:10:38 2009 +0000
@@ -313,11 +313,9 @@
throw new NullPointerException();
synchronized (readLock) {
ensureOpen();
- // If socket is not bound then behave as if nothing received
- // Will be fixed by 6621699
- if (localAddress() == null) {
- return null;
- }
+ // Socket was not bound before attempting receive
+ if (localAddress() == null)
+ bind(null);
int n = 0;
ByteBuffer bb = null;
try {
--- a/jdk/test/java/nio/channels/DatagramChannel/NotBound.java Tue Mar 24 14:08:37 2009 +0000
+++ b/jdk/test/java/nio/channels/DatagramChannel/NotBound.java Tue Mar 24 14:10:38 2009 +0000
@@ -22,27 +22,110 @@
*/
/* @test
- * @bug 4512723
- * @summary Unit test for datagram-socket-channel adaptors
+ * @bug 4512723 6621689
+ * @summary Test that connect/send/receive with unbound DatagramChannel causes
+ * the channel's socket to be bound to a local address
*/
import java.net.*;
-import java.nio.*;
-import java.nio.channels.*;
+import java.nio.ByteBuffer;
+import java.nio.channels.DatagramChannel;
+import java.io.IOException;
+
+public class NotBound {
+
+ static void checkBound(DatagramChannel dc) throws IOException {
+ if (dc.getLocalAddress() == null)
+ throw new RuntimeException("Not bound??");
+ }
-class NotBound {
- public static void main(String[] args) throws Exception {
- test1(false);
- test1(true);
+ // starts a thread to send a datagram to the given channel once the channel
+ // is bound to a local address
+ static void wakeupWhenBound(final DatagramChannel dc) {
+ Runnable wakeupTask = new Runnable() {
+ public void run() {
+ try {
+ // poll for local address
+ InetSocketAddress local;
+ do {
+ Thread.sleep(50);
+ local = (InetSocketAddress)dc.getLocalAddress();
+ } while (local == null);
+
+ // send message to channel to wakeup receiver
+ DatagramChannel sender = DatagramChannel.open();
+ try {
+ ByteBuffer bb = ByteBuffer.wrap("hello".getBytes());
+ InetAddress lh = InetAddress.getLocalHost();
+ SocketAddress target =
+ new InetSocketAddress(lh, local.getPort());
+ sender.send(bb, target);
+ } finally {
+ sender.close();
+ }
+
+ } catch (Exception x) {
+ x.printStackTrace();
+ }
+ }};
+ new Thread(wakeupTask).start();
}
- static void test1(boolean blocking) throws Exception {
- ByteBuffer bb = ByteBuffer.allocateDirect(256);
- DatagramChannel dc1 = DatagramChannel.open();
- dc1.configureBlocking(false);
- SocketAddress isa = dc1.receive(bb);
- if (isa != null)
- throw new Exception("Unbound dc returned non-null");
- dc1.close();
+ public static void main(String[] args) throws IOException {
+ DatagramChannel dc;
+
+ // connect
+ dc = DatagramChannel.open();
+ try {
+ DatagramChannel peer = DatagramChannel.open()
+ .bind(new InetSocketAddress(0));
+ int peerPort = ((InetSocketAddress)(peer.getLocalAddress())).getPort();
+ try {
+ dc.connect(new InetSocketAddress(InetAddress.getLocalHost(), peerPort));
+ checkBound(dc);
+ } finally {
+ peer.close();
+ }
+ } finally {
+ dc.close();
+ }
+
+ // send
+ dc = DatagramChannel.open();
+ try {
+ ByteBuffer bb = ByteBuffer.wrap("ignore this".getBytes());
+ SocketAddress target =
+ new InetSocketAddress(InetAddress.getLocalHost(), 5000);
+ dc.send(bb, target);
+ checkBound(dc);
+ } finally {
+ dc.close();
+ }
+
+ // receive (blocking)
+ dc = DatagramChannel.open();
+ try {
+ ByteBuffer bb = ByteBuffer.allocateDirect(128);
+ wakeupWhenBound(dc);
+ SocketAddress sender = dc.receive(bb);
+ if (sender == null)
+ throw new RuntimeException("Sender should not be null");
+ checkBound(dc);
+ } finally {
+ dc.close();
+ }
+
+ // receive (non-blocking)
+ dc = DatagramChannel.open();
+ try {
+ dc.configureBlocking(false);
+ ByteBuffer bb = ByteBuffer.allocateDirect(128);
+ SocketAddress sender = dc.receive(bb);
+ if (sender != null)
+ throw new RuntimeException("Sender should be null");
+ checkBound(dc);
+ } finally {
+ dc.close();
+ }
}
}