JDK-7164518 : No PortUnreachableException when connecting to a non-existing DatagramSocket (mac)
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.net
  • Affected Version: 7,8,9,11
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • OS: os_x
  • CPU: x86
  • Submitted: 2012-04-26
  • Updated: 2021-12-03
  • Resolved: 2020-08-17
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 16
16 b12Fixed
Related Reports
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
This program calls send/receive after trying to connect to a non-existing DatagramSocket, it times out after 5 seconds without throwing a PortUnreachableException.

Apple JDK 6 throws a PortUnreachableException immediately.

import java.net.*;

public class A1 {

    public static void main(String[] args) throws Exception {
        byte[] data = "hello".getBytes();
        InetAddress iaddr = InetAddress.getByName("localhost");
        DatagramSocket dgSocket = new DatagramSocket();
        dgSocket.setSoTimeout(5000);
        dgSocket.connect(iaddr, 8080);
        DatagramPacket dgPacketOut = new DatagramPacket(data, data.length,
                                                        iaddr, 8080);
        dgSocket.send(dgPacketOut);
        byte ibuf[] = new byte[1024];
        DatagramPacket dgPacketIn = new DatagramPacket(ibuf, ibuf.length);
        dgSocket.receive(dgPacketIn);
    }
}

Comments
URL: https://hg.openjdk.java.net/jdk/jdk/rev/b193541d5295 User: pconcannon Date: 2020-08-17 09:36:43 +0000
17-08-2020

with the test in the description you'll see the test throw the PortUnreachableException for new DatagramSocket implementation and SocketTimeoutException for the -Djdk.net.usePlainDatagramSocketImpl=true original DatagramSocket impl throws java.net.SocketTimeoutException owner@Owners-MacBook-Pro JDK_NETWORK_TESTS % ~/MARK_SHEPPARD/JDK15-releases/jdk15-ea-b33/jdk-15.jdk/Contents/Home/bin/java -Djdk.net.usePlainDatagramSocketImpl=true PortUnreachableTest Exception in thread "main" java.net.SocketTimeoutException: Receive timed out at java.base/java.net.PlainDatagramSocketImpl.peekData(Native Method) at java.base/java.net.NetMulticastSocket.receive(NetMulticastSocket.java:433) at java.base/java.net.DatagramSocket.receive(DatagramSocket.java:569) at PortUnreachableTest.main(PortUnreachableTest.java:17) new DatagramSocket impl throws the java.net.PortUnreachableException owner@Owners-MacBook-Pro JDK_NETWORK_TESTS % ~/MARK_SHEPPARD/JDK15-releases/jdk15-ea-b33/jdk-15.jdk/Contents/Home/bin/java -Djdk.net.usePlainDatagramSocketImpl=false PortUnreachableTest Exception in thread "main" java.net.PortUnreachableException at java.base/sun.nio.ch.DatagramChannelImpl.receive0(Native Method) at java.base/sun.nio.ch.DatagramChannelImpl.receiveIntoNativeBuffer(DatagramChannelImpl.java:747) at java.base/sun.nio.ch.DatagramChannelImpl.receive(DatagramChannelImpl.java:725) at java.base/sun.nio.ch.DatagramChannelImpl.trustedBlockingReceive(DatagramChannelImpl.java:696) at java.base/sun.nio.ch.DatagramChannelImpl.blockingReceive(DatagramChannelImpl.java:630) at java.base/sun.nio.ch.DatagramSocketAdaptor.receive(DatagramSocketAdaptor.java:239) at java.base/java.net.DatagramSocket.receive(DatagramSocket.java:569) at PortUnreachableTest.main(PortUnreachableTest.java:17) as default no system property owner@Owners-MacBook-Pro JDK_NETWORK_TESTS % ~/MARK_SHEPPARD/JDK15-releases/jdk15-ea-b33/jdk-15.jdk/Contents/Home/bin/java PortUnreachableTest Exception in thread "main" java.net.PortUnreachableException at java.base/sun.nio.ch.DatagramChannelImpl.receive0(Native Method) at java.base/sun.nio.ch.DatagramChannelImpl.receiveIntoNativeBuffer(DatagramChannelImpl.java:747) at java.base/sun.nio.ch.DatagramChannelImpl.receive(DatagramChannelImpl.java:725) at java.base/sun.nio.ch.DatagramChannelImpl.trustedBlockingReceive(DatagramChannelImpl.java:696) at java.base/sun.nio.ch.DatagramChannelImpl.blockingReceive(DatagramChannelImpl.java:630) at java.base/sun.nio.ch.DatagramSocketAdaptor.receive(DatagramSocketAdaptor.java:239) at java.base/java.net.DatagramSocket.receive(DatagramSocket.java:569) at PortUnreachableTest.main(PortUnreachableTest.java:17) for the JNDI DNS test -- this passes with new DatgramSocket implicit and fails with original implementation extracted standalone new implementation passes owner@Owners-MacBook-Pro JDK_NETWORK_TESTS % ~/MARK_SHEPPARD/JDK15-releases/jdk15-ea-b33/jdk-15.jdk/Contents/Home/bin/java JndiDnsPortUnreachableTest Skip local DNS Server creation Elapsed (ms): 56 owner@Owners-MacBook-Pro JDK_NETWORK_TESTS % ~/MARK_SHEPPARD/JDK15-releases/jdk15-ea-b33/jdk-15.jdk/Contents/Home/bin/java -Djdk.net.usePlainDatagramSocketImpl=false JndiDnsPortUnreachableTest Skip local DNS Server creation Elapsed (ms): 55 original DatgramSocket implies fails with SocketTimeoutException owner@Owners-MacBook-Pro JDK_NETWORK_TESTS % ~/MARK_SHEPPARD/JDK15-releases/jdk15-ea-b33/jdk-15.jdk/Contents/Home/bin/java -Djdk.net.usePlainDatagramSocketImpl=true JndiDnsPortUnreachableTest Skip local DNS Server creation Bug 7164518 can cause this failure on mac Exception in thread "main" javax.naming.CommunicationException: DNS error [Root exception is java.net.SocketTimeoutException: Receive timed out]; remaining name '' at jdk.naming.dns/com.sun.jndi.dns.DnsClient.query(DnsClient.java:316) at jdk.naming.dns/com.sun.jndi.dns.Resolver.query(Resolver.java:81) at jdk.naming.dns/com.sun.jndi.dns.DnsContext.c_getAttributes(DnsContext.java:434) at java.naming/com.sun.jndi.toolkit.ctx.ComponentDirContext.p_getAttributes(ComponentDirContext.java:235) at java.naming/com.sun.jndi.toolkit.ctx.PartialCompositeDirContext.getAttributes(PartialCompositeDirContext.java:141) at java.naming/com.sun.jndi.toolkit.ctx.PartialCompositeDirContext.getAttributes(PartialCompositeDirContext.java:129) at java.naming/javax.naming.directory.InitialDirContext.getAttributes(InitialDirContext.java:171) at java.naming/javax.naming.directory.InitialDirContext.getAttributes(InitialDirContext.java:166) at JndiDnsPortUnreachableTest.runTest(JndiDnsPortUnreachableTest.java:54) at TestBase.launch(TestBase.java:60) at TestBase.run(TestBase.java:27) at JndiDnsPortUnreachableTest.main(JndiDnsPortUnreachableTest.java:38) Caused by: java.net.SocketTimeoutException: Receive timed out at java.base/java.net.PlainDatagramSocketImpl.peekData(Native Method) at java.base/java.net.NetMulticastSocket.receive(NetMulticastSocket.java:433) at java.base/java.net.DatagramSocket.receive(DatagramSocket.java:569) at jdk.naming.dns/com.sun.jndi.dns.DnsClient.doUdpQuery(DnsClient.java:426) at jdk.naming.dns/com.sun.jndi.dns.DnsClient.query(DnsClient.java:214) ... 11 more
13-08-2020

I see that the problem list still has: com/sun/jndi/dns/ConfigTests/PortUnreachable.java 7164518 macosx-all We should verify that this test now passes, and if so, remove the test from the problem list (possibly add -Djdk.net.usePlainDatagramSocketImpl=false on the command line to make sure it only run with the new impl, as it should still fail with the old impl).
10-08-2020

I assume this is no longer an issue in JDK 15.
10-08-2020

I have the same failure in JDK 7: RULE "jndi/DNS/ConfigTests/index.html#PortUnreachable" Exception javax.naming.CommunicationException: DNS error [Root exception is java.net.SocketTimeoutException: Receive timed out]; remaining name '' http://aurora.ru.oracle.com/functional/faces/RunDetails.xhtml?names=1192118.ute.st2_20151207191159-2
11-12-2015

reducing priority, as it is an operating system API issue, and current behaviour is aligned with Javav DatagramSocket API specification.
01-10-2013

amended the test to perform an explicit bind on the DatagramSocket. But this bound address is still reset to wildcard INADDR_ANY after the disconnect. So on macOS, the issue is that if the native connect is re-enabled, then the DatagramSocket's local address will be reset to wildcard, after a disconnect. This will happen even when a previous connect was not invoked. Once, the connect to anAF_UNSPEC address, then we have local address rerset. The port remains bound. The DatagramSocket remains functional, but its address has transmogrified. Tried a version of connect using a null address, but this didn't disconnect the socket. Even though the man pages indicates that this an alternative. So it looks like the emulation needs to persist to maintain uniform connect disconnect semantics across all platforms. So is it a close won't fix ??
27-09-2013

poking around at this a bit further we find some peculiarities in the test. In the test two Datagram sockets, s and ss are created using the same IP address and ephemeral ports. the connect address for socket s is set to that of ss then s is disconnected a Datagram is send to s, using the address of s This results in a EHOSTUNREACH. The reason being is that after the disconnect, the address of s is reset to all 0 effectively a wildcard address or THIS HOST. So the Datagram contains a wildcard address rather than the LocalHost (i.e. this host) address. If we use the LocalHost and the saved s socket port for the Datagram the test works ok. Nonetheless it highlights an issue with the "disconnect" i.e. the reset of the implicitly bound address for the unconnected socket. so macOS seems to exhibit similar behaviour to that of Linux
27-09-2013

this change causes java/net/DatagramSocket/B6411513.java to fail This test does a connect and disconnect on a DatagramSocket. The send results in an EHOSTUNREACH - no route to host. The disconnect seems to corrupt the socket binding, so perhaps this is a contributing factor to the CONNECT emulation and the connectDisabled on macOS ?? the disconnect code, which is a connect to socket address AF_UNSPEC and a zeroed sockaddr_in6 rather than a sockaddr_in the "disconnect" of the UDP socket is left in a non functioning state. This could be the bug Alan refers to above -- BUT the code gives no clues yet
26-09-2013

The ICMP error - port unreachable, typically is not return to the UDP client process. If we search the UDP annals we'll find that such ICMP error are not returned for a UDP socket, unless the socket os connected. On macOS the AbstractPlainDatagramSocketImpl has a class variable connectedDisabled. This is set true for mac OS. Hence, the connect operation on the DatagramSocket doesn't result in a socket level connect at the OS level. Thus, as far as mac Os is concerned the UDP socket is not connected hence it doesn't return the ICMP error. If we set the connected Disabled to false on macOS, and execute the sample test above, we'll see the ICMP Port Unreachable exception on the receive operation. mikemac:PortUnreachableExceptionTest msheppar$ java -cp . PortUnreachableExceptionTest DatagramSocket.connectInternal: set state connected socketSend: calling sendTo and connected == 1 socketSend: calling sendTo and connected == 1 socketSend: calling sendTo and connected == 1 socketSend: calling sendTo and connected == 1 Exception in thread "main" java.net.PortUnreachableException: ICMP Port Unreachable at java.net.PlainDatagramSocketImpl.receive0(Native Method) at java.net.AbstractPlainDatagramSocketImpl.receive(AbstractPlainDatagramSocketImpl.java:144) at java.net.DatagramSocket.receive(DatagramSocket.java:783) at PortUnreachableExceptionTest.main(PortUnreachableExceptionTest.java:24) Need to chat to Michael and Chris on this, will investigate the side effects of setting the connectedDisabled to false.
25-09-2013

It seems binding the socket to the 8080 port makes it a "server" "listening" on that port. This example is about when you try to connect (or send data) to a non-existing UDP socket what should happen. It should throw some error anyway, current it's SocketTimeoutException after a long time, but I would prefer it fails ASAP and throw a PortUnreachableException.
05-03-2013

This example java program creates a UDP (aka Datagram) socket and connects it to port 8080... but the socket is never bound to port 8080. (You can see this is true by using the "netstat" command, e.g., netstat -an | grep 8080 | grep -i udp. ) This example "works" if the DatagramSocket constructor is invoked with the port number 8080, e.g., "DatagramSocket dgSocket = new DatagramSocket(8080).
04-03-2013

EVALUATION This isn't a bug as there is no guarantee that PortUnreachableException will be thrown. That said, the lack of a PUE will hurt performance for cases where the client can fallback or continue without waiting for a timeout. I believe we don't get teh ICMP port unreachable packets on Mac because the connect is emulated (the native connect was disabled during the Mac port due to bugs in OS X).
29-04-2012