Re: JEP-353 - Socket.connect now throws NoRouteToHostException as against ConnectException previously

2021-08-24 Thread Alan Bateman




On 24/08/2021 04:09, Jaikiran Pai wrote:




Do you connections to the Apache HTTP client library and the retry 
code that is looking for specific exceptions? From a distance it 
seems very fragile and depending on very implementation specific 
behavior. I wonder if it has ever been tested on Windows or with an 
untimed connect.


I am not involved in the Apache HTTP client library project. However, 
I will go ahead and open a discussion in their mailing list and bring 
this issue to their attention, so that they can decide how to deal 
with it.


Thank you for your help and the explanation.


This has now been fixed in the Apache HTTP client library to no longer 
treat these two exception types differently when it comes to retry 
handling logic


Good. Note that BindException is possible when attempt to establish a 
connection because the kernel will bind the socket to a local port if 
not explicitly bound already. It might arise when there are no ports 
available. I don't know if this changes the retry logic in the HTTP 
client but thought I should mention it.


-Alan


Re: JEP-353 - Socket.connect now throws NoRouteToHostException as against ConnectException previously

2021-08-23 Thread Jaikiran Pai





Do you connections to the Apache HTTP client library and the retry 
code that is looking for specific exceptions? From a distance it 
seems very fragile and depending on very implementation specific 
behavior. I wonder if it has ever been tested on Windows or with an 
untimed connect.


I am not involved in the Apache HTTP client library project. However, 
I will go ahead and open a discussion in their mailing list and bring 
this issue to their attention, so that they can decide how to deal 
with it.


Thank you for your help and the explanation.


This has now been fixed in the Apache HTTP client library to no longer 
treat these two exception types differently when it comes to retry 
handling logic https://github.com/apache/httpcomponents-client/pull/311


-Jaikiran



Re: JEP-353 - Socket.connect now throws NoRouteToHostException as against ConnectException previously

2021-08-21 Thread Jaikiran Pai

Hello Alan,

On 21/08/21 9:56 pm, Alan Bateman wrote:

On 21/08/2021 12:40, Jaikiran Pai wrote:
I was able to reproduce this on a MacOS. However, the continuous 
integration setup project for Quarkus projects runs these tests 
against Linux and Windows setups and they have run into this issue at 
least on the Linux OS jobs (I will need to go and check if Windows 
jobs had failed too). I can get the specific OS versions if 
necessary, but I don't think that will be needed (due to the 
reproducer I explain below).


:

From what I see in the output of this program, the resolution of 
microprofile.io returns 4 IP addresses. 2 of them are of type IPv4 
and 2 are of type IPv6. Across all Java versions, for IPv4 addresses, 
the connection attempts fail with the same 
"java.net.SocketTimeoutException: Connect timed out". However, for 
the IPv6 addresses, in Java 11, the connection attempts fail with 
"java.net.ConnectException: No route to host (connect failed)" 
whereas in Java 16, 17 and upstream latest, the connection attempts 
against the IPv6 addresses fails with 
"java.net.NoRouteToHostException: No route to host".


Thanks for the additional information, I think I understand the issue 
now.


If you extend your test to include a connect without a timeout then 
you'll see that old and new implementations throw 
NoRouteToHostException when the underlying error is EHOSTUNREACH "No 
route to host".


You are right - I tweaked my example to remove the timeout param being 
passed to the connect method and with that change, the exception that 
gets thrown is consistent (NoRouteToHostException) across Java version 
for IPv6 addresses.



However, for the connect with timeout case on Linux/macOS/Unix the old 
implementation doesn't correctly handle network errors when they are 
reported immediately. It throws ConnectException for all errors, 
including EHOSTUNREACH "No route to host", whereas it should map the 
error to a specific exception as it does for the untimed case. It's 
possible that this bug has existed for a long time.


So while there is indeed a behavior change between the old and new 
implementation for the timed case where the connect fails immediately, 
I don't think we should attempt to change the new implementation to 
have this buggy behavior.



Thank you for that explanation and yes, what you say makes sense.


Do you connections to the Apache HTTP client library and the retry 
code that is looking for specific exceptions? From a distance it seems 
very fragile and depending on very implementation specific behavior. I 
wonder if it has ever been tested on Windows or with an untimed connect.


I am not involved in the Apache HTTP client library project. However, I 
will go ahead and open a discussion in their mailing list and bring this 
issue to their attention, so that they can decide how to deal with it.


Thank you for your help and the explanation.

-Jaikiran




Re: JEP-353 - Socket.connect now throws NoRouteToHostException as against ConnectException previously

2021-08-21 Thread Alan Bateman

On 21/08/2021 12:40, Jaikiran Pai wrote:
I was able to reproduce this on a MacOS. However, the continuous 
integration setup project for Quarkus projects runs these tests 
against Linux and Windows setups and they have run into this issue at 
least on the Linux OS jobs (I will need to go and check if Windows 
jobs had failed too). I can get the specific OS versions if necessary, 
but I don't think that will be needed (due to the reproducer I explain 
below).


:

From what I see in the output of this program, the resolution of 
microprofile.io returns 4 IP addresses. 2 of them are of type IPv4 and 
2 are of type IPv6. Across all Java versions, for IPv4 addresses, the 
connection attempts fail with the same 
"java.net.SocketTimeoutException: Connect timed out". However, for the 
IPv6 addresses, in Java 11, the connection attempts fail with 
"java.net.ConnectException: No route to host (connect failed)" whereas 
in Java 16, 17 and upstream latest, the connection attempts against 
the IPv6 addresses fails with "java.net.NoRouteToHostException: No 
route to host".


Thanks for the additional information, I think I understand the issue now.

If you extend your test to include a connect without a timeout then 
you'll see that old and new implementations throw NoRouteToHostException 
when the underlying error is EHOSTUNREACH "No route to host".


However, for the connect with timeout case on Linux/macOS/Unix the old 
implementation doesn't correctly handle network errors when they are 
reported immediately. It throws ConnectException for all errors, 
including EHOSTUNREACH "No route to host", whereas it should map the 
error to a specific exception as it does for the untimed case. It's 
possible that this bug has existed for a long time.


So while there is indeed a behavior change between the old and new 
implementation for the timed case where the connect fails immediately, I 
don't think we should attempt to change the new implementation to have 
this buggy behavior.


Do you connections to the Apache HTTP client library and the retry code 
that is looking for specific exceptions? From a distance it seems very 
fragile and depending on very implementation specific behavior. I wonder 
if it has ever been tested on Windows or with an untimed connect.



-Alan


Re: JEP-353 - Socket.connect now throws NoRouteToHostException as against ConnectException previously

2021-08-21 Thread Jaikiran Pai

Hello Alan,

On 21/08/21 2:21 pm, Alan Bateman wrote:

On 21/08/2021 08:17, Jaikiran Pai wrote:

JEP-353[1] which got implemented and released in JDK13, states:

"The java.net package defines many sub-classes of SocketException. 
The new implementation will attempt to throw the same specific 
SocketException as the old implementation but there may be cases 
where they are not the same."


In one of the projects I watch, a recent issue[2] shows that the 
"Socket.connect(...)" call, in certain cases, now throws a 
"java.net.NoRouteToHostException" exception as opposed to 
"java.net.ConnectException" in previous versions before this change. 
The "Socket.connect(...)" javadoc states that this API can throw an 
"IOException", so this change, in theory, is still fine and doesn't 
break any API contract. However, as noted in [2], certain libraries 
(Apache HTTP client 4.5.x versions in this case) expect a certain 
exception type when it's dealing with decision making for HTTP 
request retries. Due to this change in the exception type being 
thrown, the Apache HTTP client library now behaves differently in 
Java 11 and Java 16.


Is this change of exception type being thrown intentional? Or is 
there interest in changing back to the previous exception type to 
preserve backward compatibility? If not, I think the Apache HTTP 
client library will have to perhaps do certain changes to have this 
part of the code behave the same across Java versions.


Thanks for the mail, I haven't seen any other reports on this.

Can you say which operating system and say a bit more about the 
conditions where this is observed? 


I was able to reproduce this on a MacOS. However, the continuous 
integration setup project for Quarkus projects runs these tests against 
Linux and Windows setups and they have run into this issue at least on 
the Linux OS jobs (I will need to go and check if Windows jobs had 
failed too). I can get the specific OS versions if necessary, but I 
don't think that will be needed (due to the reproducer I explain below).



When connecting to a host that is not reachable then it's possible for 
the underlying connect to fail with a "Connection timed out", "No 
route to host", or other errors.


The reason I'm asking about the OS/conditions is that the old 
implementation did attempt to map specific errors to 
NoRouteToHostException. There's an example stack stack (Windows, with 
JDK 9) in this bug report:

  https://bugs.openjdk.java.net/browse/JDK-8042714

In general, the mapping of connect errors to sub-classes of 
SocketException has always been best effort and I both both 
ConnectException and NoRouteToHostException are possible, all depends 
on the underlying error.


So my initial reaction is that we shouldn't do anything right now, I 
think we need to know a bit more abut the environment/conditions as 
I'm puzzled as to why the HTTP client retry decision didn't run into 
this before with the old implementation.


Now that you mentioned it, I decided to try and replicate this in a 
trivial Java program. My initial attempt didn't reproduce this. So I 
looked into the Apache HTTP client code and I can now reproduce this 
consistenly with the following trivial Java program (pasted at the end 
of this mail). What this program does is:


- DNS resolves the IP addresses of "microprofile.io" (this is resolvable)

- For each of the returned IP address, it then constructs a 
InetSocketAddress to port 1234. Nothing is listening on this port (on 
the remote end), so we do expect the connection attempts to fail.


- It then instantiates a Socket instance out of this InetSocketAddress 
and calls connect on the socket instance.


I ran this against Java 11, Java 16, Java 17 and latest upstream OpenJDK 
code.


From what I see in the output of this program, the resolution of 
microprofile.io returns 4 IP addresses. 2 of them are of type IPv4 and 2 
are of type IPv6. Across all Java versions, for IPv4 addresses, the 
connection attempts fail with the same "java.net.SocketTimeoutException: 
Connect timed out". However, for the IPv6 addresses, in Java 11, the 
connection attempts fail with "java.net.ConnectException: No route to 
host (connect failed)" whereas in Java 16, 17 and upstream latest, the 
connection attempts against the IPv6 addresses fails with 
"java.net.NoRouteToHostException: No route to host".


Here's the trivial Java code which reproduces this for me. Let me know 
if you need additional details.


import java.net.*;

public class ConnectTest  {
    public static void main(final String[] args) throws Exception {
        final int timeout = 1;
        // our target host that DNS resolves correctly
        final String host = "microprofile.io";
        // a port where nothing listens on
        final int port = 1234;
        // DNS resolve by hostname
        final InetAddress[] addrs = InetAddress.getAllByName(host);
        // try connecting to each IP on port
        for (final InetAddress addr : 

Re: JEP-353 - Socket.connect now throws NoRouteToHostException as against ConnectException previously

2021-08-21 Thread Alan Bateman

On 21/08/2021 08:17, Jaikiran Pai wrote:

JEP-353[1] which got implemented and released in JDK13, states:

"The java.net package defines many sub-classes of SocketException. The 
new implementation will attempt to throw the same specific 
SocketException as the old implementation but there may be cases where 
they are not the same."


In one of the projects I watch, a recent issue[2] shows that the 
"Socket.connect(...)" call, in certain cases, now throws a 
"java.net.NoRouteToHostException" exception as opposed to 
"java.net.ConnectException" in previous versions before this change. 
The "Socket.connect(...)" javadoc states that this API can throw an 
"IOException", so this change, in theory, is still fine and doesn't 
break any API contract. However, as noted in [2], certain libraries 
(Apache HTTP client 4.5.x versions in this case) expect a certain 
exception type when it's dealing with decision making for HTTP request 
retries. Due to this change in the exception type being thrown, the 
Apache HTTP client library now behaves differently in Java 11 and Java 
16.


Is this change of exception type being thrown intentional? Or is there 
interest in changing back to the previous exception type to preserve 
backward compatibility? If not, I think the Apache HTTP client library 
will have to perhaps do certain changes to have this part of the code 
behave the same across Java versions.


Thanks for the mail, I haven't seen any other reports on this.

Can you say which operating system and say a bit more about the 
conditions where this is observed? When connecting to a host that is not 
reachable then it's possible for the underlying connect to fail with a 
"Connection timed out", "No route to host", or other errors.


The reason I'm asking about the OS/conditions is that the old 
implementation did attempt to map specific errors to 
NoRouteToHostException. There's an example stack stack (Windows, with 
JDK 9) in this bug report:

  https://bugs.openjdk.java.net/browse/JDK-8042714

In general, the mapping of connect errors to sub-classes of 
SocketException has always been best effort and I both both 
ConnectException and NoRouteToHostException are possible, all depends on 
the underlying error.


So my initial reaction is that we shouldn't do anything right now, I 
think we need to know a bit more abut the environment/conditions as I'm 
puzzled as to why the HTTP client retry decision didn't run into this 
before with the old implementation.


-Alan