JDK-7177784 : SocketChannel.socket().getLocalAddress() returns wildcard address after connect
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.nio
  • Affected Version: 7
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_7
  • CPU: x86
  • Submitted: 2012-06-18
  • Updated: 2012-08-03
  • Resolved: 2012-06-22
Related Reports
Duplicate :  
Description
FULL PRODUCT VERSION :
1.7.0_05 23.1-b03

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows 7 (32-bit)
Microsoft Windows 7 (64-bit)

A DESCRIPTION OF THE PROBLEM :
When using the java NIO to create a TCP client connection, the local address of a connected socket returns the wildcard address instead of the expected local IP address. This works as expected in the previous Java 6.0, but no longer works on Java 7.0

REGRESSION.  Last worked in version 6u31

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Create an nio SocketChannel and connect to a remote TCP port.
2. Once connected, call SocketChannel.socket().getLocalAddress()


EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The actual adapter IP address that is in use for the connection:
Local Socket Address: /192.168.1.1
ACTUAL -
The IP wildcard address
Local Socket Address: /0.0.0.0

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.channels.spi.SelectorProvider;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

public class TestSocketAddress implements Runnable {

	public static void main(String[] args) {
		try {
			System.out.println("Java Version: " + System.getProperty("java.version"));
			System.out.println("JVM  Version: " + System.getProperty("java.vm.version"));
			TestSocketAddress client = new TestSocketAddress();
			Thread t = new Thread(client);
			t.start();
			client.AsyncConnect(InetAddress.getByName("www.google.com"), 80);
			t.join();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	private List<ChangeRequest> pendingChanges = new LinkedList<ChangeRequest>();
	private Selector selector;
	private InetAddress host;
	private int port;
	private boolean finished = false;
	
	public TestSocketAddress() {
		try {
			this.selector = this.initSelector();
		} catch (Exception e ) {
			
		}
	}
	
	public void AsyncConnect(InetAddress host, int port) throws IOException {
		this.host = host;
		this.port = port;
		finished = false;
		this.initiateConnection();
		this.selector.wakeup();
	}
	
	private SocketChannel initiateConnection() throws IOException {
		SocketChannel socketChannel = SocketChannel.open();
		socketChannel.configureBlocking(false);
		socketChannel.connect(new InetSocketAddress(this.host, this.port));
		synchronized(this.pendingChanges) {
			this.pendingChanges.add(new ChangeRequest(socketChannel, ChangeRequest.REGISTER, SelectionKey.OP_CONNECT));
		}
		return socketChannel;
	}
	
	private Selector initSelector() throws IOException {
		return SelectorProvider.provider().openSelector();
	}
	
	private void finishConnection(SelectionKey key) throws IOException {
		SocketChannel socketChannel = (SocketChannel) key.channel();
		try {
			socketChannel.finishConnect();
		} catch (IOException e) {
			System.out.println(e);
			key.cancel();
			return;
		}
		System.out.println("Local Socket Address: " + socketChannel.socket().getLocalAddress());
		try {
			socketChannel.close();
		} catch (IOException e) {}
		finally { finished = true; this.selector.wakeup(); }
	}
	
	public void run() {
		while (!finished) {
			try {
				synchronized (this.pendingChanges) {
					Iterator<ChangeRequest> changes = this.pendingChanges.iterator();
					while (changes.hasNext()) {
						ChangeRequest change = (ChangeRequest) changes.next();
						switch (change.type) {
							case ChangeRequest.CHANGEOPS:
								SelectionKey key = change.socket.keyFor(this.selector);
								key.interestOps(change.ops);
								break;
							case ChangeRequest.REGISTER:
								change.socket.register(this.selector, change.ops);
								break;
						}
					}
					this.pendingChanges.clear();
				}
				
				this.selector.select();

				Iterator<SelectionKey> selectedKeys = this.selector.selectedKeys().iterator();
				while (selectedKeys.hasNext()) {
					SelectionKey key = (SelectionKey) selectedKeys.next();
					selectedKeys.remove();
					if (!key.isValid()) {
						continue;
					}
					if (key.isConnectable()) {
						this.finishConnection(key);
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	public class ChangeRequest {
		public static final int REGISTER = 1;
		public static final int CHANGEOPS = 2;
		
		public SocketChannel socket;
		public int type;
		public int ops;
		
		public ChangeRequest(SocketChannel socket, int type, int ops) {
			this.socket = socket;
			this.type = type;
			this.ops = ops;
		}
	}
}

---------- END SOURCE ----------

Comments
EVALUATION This is only an issue when the SocketChannel is configured non-blocking and has been fixed by way of the changes for Windows 8 in 7096436.
18-06-2012