# HG changeset patch # User alanb # Date 1237903838 0 # Node ID f35f516befc3bad06bbb345cce3d628fcc8b10df # Parent a528c08308627b93b3f09d5dd56ba44b1799d27d 6621689: (dc spec) DatagramChannel.receive when channel is not bound is not specified Reviewed-by: sherman diff -r a528c0830862 -r f35f516befc3 jdk/src/share/classes/java/nio/channels/DatagramChannel.java --- 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 @@ * *

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.

+ * 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}.

* * @param remote * The remote address to which this channel is to be connected @@ -356,7 +359,10 @@ *

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.

+ * 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}.

* * @param dst * The buffer into which the datagram is to be transferred @@ -413,7 +419,10 @@ *

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.

+ * 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}.

* * @param src * The buffer containing the datagram to be sent diff -r a528c0830862 -r f35f516befc3 jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java --- 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 { diff -r a528c0830862 -r f35f516befc3 jdk/test/java/nio/channels/DatagramChannel/NotBound.java --- 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(); + } } }