From matthias.baesken at sap.com Mon Jul 2 08:17:33 2018 From: matthias.baesken at sap.com (Baesken, Matthias) Date: Mon, 2 Jul 2018 08:17:33 +0000 Subject: RFR : 8205959 : Do not restart close if errno is EINTR Message-ID: <2e9e20817ecf49d995cd2f939fefd774@sap.com> Hello , there is a similar pattern (attempt to restart close in case of EINTR) in the coding as well in socket_md.c : src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c-147- int rv; src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c-148- do { src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c-149- rv = close(fd); src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c:150: } while (rv == -1 && errno == EINTR); src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c-151- src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c-152- return rv; src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c-153-} Do you think this needs adjustment (on LINUX) as well ? Best regards, Matthias > Message: 2 > Date: Thu, 28 Jun 2018 18:19:46 +0100 > From: Alan Bateman > To: David Lloyd , ivan.gerasimov at oracle.com > Cc: OpenJDK Network Dev list > Subject: Re: RFR : 8205959 : Do not restart close if errno is EINTR > Message-ID: <3fd1496f-ab83-a2d5-0699-13c8b735d70b at oracle.com> > Content-Type: text/plain; charset=utf-8; format=flowed > > On 28/06/2018 17:35, David Lloyd wrote: > > : > > Do you (or Alan) think that this might have accounted for real-world > > connection problems? > > > In the file I/O area, with NFS I think, we had an issue a long time ago > where close was retried after EIO. That issue was fixed a long time ago > but it's one that comes to mind in this general area. > > -Alan > From norman.maurer at googlemail.com Mon Jul 2 08:23:11 2018 From: norman.maurer at googlemail.com (Norman Maurer) Date: Mon, 2 Jul 2018 10:23:11 +0200 Subject: RFR : 8205959 : Do not restart close if errno is EINTR In-Reply-To: <2e9e20817ecf49d995cd2f939fefd774@sap.com> References: <2e9e20817ecf49d995cd2f939fefd774@sap.com> Message-ID: <2E0FD75E-3AEF-4251-B324-7F0BA864CFC2@googlemail.com> +1 retry a close on EINTR has most likely not the outcome you expect and may even close a wrong FD if the same FD is reused already (as even if EINTR is returned it may have closed the FD) > Am 02.07.2018 um 10:17 schrieb Baesken, Matthias : > > Hello , there is a similar pattern (attempt to restart close in case of EINTR) in the coding as well in socket_md.c : > > src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c-147- int rv; > src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c-148- do { > src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c-149- rv = close(fd); > src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c:150: } while (rv == -1 && errno == EINTR); > src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c-151- > src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c-152- return rv; > src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c-153-} > > Do you think this needs adjustment (on LINUX) as well ? > > Best regards, Matthias > > >> Message: 2 >> Date: Thu, 28 Jun 2018 18:19:46 +0100 >> From: Alan Bateman >> To: David Lloyd , ivan.gerasimov at oracle.com >> Cc: OpenJDK Network Dev list >> Subject: Re: RFR : 8205959 : Do not restart close if errno is EINTR >> Message-ID: <3fd1496f-ab83-a2d5-0699-13c8b735d70b at oracle.com> >> Content-Type: text/plain; charset=utf-8; format=flowed >> >>> On 28/06/2018 17:35, David Lloyd wrote: >>> : >>> Do you (or Alan) think that this might have accounted for real-world >>> connection problems? >>> >> In the file I/O area, with NFS I think, we had an issue a long time ago >> where close was retried after EIO. That issue was fixed a long time ago >> but it's one that comes to mind in this general area. >> >> -Alan >> > From christoph.langer at sap.com Mon Jul 2 09:03:58 2018 From: christoph.langer at sap.com (Langer, Christoph) Date: Mon, 2 Jul 2018 09:03:58 +0000 Subject: RFR : 8205959 : Do not restart close if errno is EINTR In-Reply-To: <2E0FD75E-3AEF-4251-B324-7F0BA864CFC2@googlemail.com> References: <2e9e20817ecf49d995cd2f939fefd774@sap.com> <2E0FD75E-3AEF-4251-B324-7F0BA864CFC2@googlemail.com> Message-ID: <9bf3ebbba0014f918bf53eb0b4d0c464@sap.com> Hi Matthias, forwarding to serviceability-dev, because debugging is usually discussed there. Yes, I would think this coding should be fixed, too. Can you open a bug and prepare a change? Thanks Christoph > -----Original Message----- > From: net-dev [mailto:net-dev-bounces at openjdk.java.net] On Behalf Of > Norman Maurer > Sent: Montag, 2. Juli 2018 10:23 > To: Baesken, Matthias > Cc: Stuefe, Thomas ; net-dev at openjdk.java.net > Subject: Re: RFR : 8205959 : Do not restart close if errno is EINTR > > +1 retry a close on EINTR has most likely not the outcome you expect and > may even close a wrong FD if the same FD is reused already (as even if EINTR > is returned it may have closed the FD) > > > Am 02.07.2018 um 10:17 schrieb Baesken, Matthias > : > > > > Hello , there is a similar pattern (attempt to restart close in case of EINTR) > in the coding as well in socket_md.c : > > > > src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c-147- int rv; > > src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c-148- do { > > src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c-149- rv = > close(fd); > > src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c:150: } while (rv > == -1 && errno == EINTR); > > src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c-151- > > src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c-152- return rv; > > src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c-153-} > > > > Do you think this needs adjustment (on LINUX) as well ? > > > > Best regards, Matthias > > > > > >> Message: 2 > >> Date: Thu, 28 Jun 2018 18:19:46 +0100 > >> From: Alan Bateman > >> To: David Lloyd , ivan.gerasimov at oracle.com > >> Cc: OpenJDK Network Dev list > >> Subject: Re: RFR : 8205959 : Do not restart close if errno is EINTR > >> Message-ID: <3fd1496f-ab83-a2d5-0699-13c8b735d70b at oracle.com> > >> Content-Type: text/plain; charset=utf-8; format=flowed > >> > >>> On 28/06/2018 17:35, David Lloyd wrote: > >>> : > >>> Do you (or Alan) think that this might have accounted for real-world > >>> connection problems? > >>> > >> In the file I/O area, with NFS I think, we had an issue a long time ago > >> where close was retried after EIO. That issue was fixed a long time ago > >> but it's one that comes to mind in this general area. > >> > >> -Alan > >> > > From thomas.stuefe at gmail.com Mon Jul 2 10:08:15 2018 From: thomas.stuefe at gmail.com (=?UTF-8?Q?Thomas_St=C3=BCfe?=) Date: Mon, 2 Jul 2018 12:08:15 +0200 Subject: RFR : 8205959 : Do not restart close if errno is EINTR In-Reply-To: <9bf3ebbba0014f918bf53eb0b4d0c464@sap.com> References: <2e9e20817ecf49d995cd2f939fefd774@sap.com> <2E0FD75E-3AEF-4251-B324-7F0BA864CFC2@googlemail.com> <9bf3ebbba0014f918bf53eb0b4d0c464@sap.com> Message-ID: +1. Please fix this for Linux! Thanks. On Mon, Jul 2, 2018 at 11:03 AM, Langer, Christoph wrote: > Hi Matthias, > > forwarding to serviceability-dev, because debugging is usually discussed there. > > Yes, I would think this coding should be fixed, too. Can you open a bug and prepare a change? > > Thanks > Christoph > >> -----Original Message----- >> From: net-dev [mailto:net-dev-bounces at openjdk.java.net] On Behalf Of >> Norman Maurer >> Sent: Montag, 2. Juli 2018 10:23 >> To: Baesken, Matthias >> Cc: Stuefe, Thomas ; net-dev at openjdk.java.net >> Subject: Re: RFR : 8205959 : Do not restart close if errno is EINTR >> >> +1 retry a close on EINTR has most likely not the outcome you expect and >> may even close a wrong FD if the same FD is reused already (as even if EINTR >> is returned it may have closed the FD) >> >> > Am 02.07.2018 um 10:17 schrieb Baesken, Matthias >> : >> > >> > Hello , there is a similar pattern (attempt to restart close in case of EINTR) >> in the coding as well in socket_md.c : >> > >> > src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c-147- int rv; >> > src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c-148- do { >> > src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c-149- rv = >> close(fd); >> > src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c:150: } while (rv >> == -1 && errno == EINTR); >> > src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c-151- >> > src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c-152- return rv; >> > src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c-153-} >> > >> > Do you think this needs adjustment (on LINUX) as well ? >> > >> > Best regards, Matthias >> > >> > >> >> Message: 2 >> >> Date: Thu, 28 Jun 2018 18:19:46 +0100 >> >> From: Alan Bateman >> >> To: David Lloyd , ivan.gerasimov at oracle.com >> >> Cc: OpenJDK Network Dev list >> >> Subject: Re: RFR : 8205959 : Do not restart close if errno is EINTR >> >> Message-ID: <3fd1496f-ab83-a2d5-0699-13c8b735d70b at oracle.com> >> >> Content-Type: text/plain; charset=utf-8; format=flowed >> >> >> >>> On 28/06/2018 17:35, David Lloyd wrote: >> >>> : >> >>> Do you (or Alan) think that this might have accounted for real-world >> >>> connection problems? >> >>> >> >> In the file I/O area, with NFS I think, we had an issue a long time ago >> >> where close was retried after EIO. That issue was fixed a long time ago >> >> but it's one that comes to mind in this general area. >> >> >> >> -Alan >> >> >> > From david.holmes at oracle.com Mon Jul 2 12:03:55 2018 From: david.holmes at oracle.com (David Holmes) Date: Mon, 2 Jul 2018 22:03:55 +1000 Subject: RFR : 8205959 : Do not restart close if errno is EINTR In-Reply-To: <9bf3ebbba0014f918bf53eb0b4d0c464@sap.com> References: <2e9e20817ecf49d995cd2f939fefd774@sap.com> <2E0FD75E-3AEF-4251-B324-7F0BA864CFC2@googlemail.com> <9bf3ebbba0014f918bf53eb0b4d0c464@sap.com> Message-ID: <5a2ab4d2-ed90-20fd-6340-e73153d4313d@oracle.com> In reference to 8205959, where is it stated that dup2 is any more restartable than close ?? AFAICS both leave things undefined/unspecified if they set EINTR. David On 2/07/2018 7:03 PM, Langer, Christoph wrote: > Hi Matthias, > > forwarding to serviceability-dev, because debugging is usually discussed there. > > Yes, I would think this coding should be fixed, too. Can you open a bug and prepare a change? > > Thanks > Christoph > >> -----Original Message----- >> From: net-dev [mailto:net-dev-bounces at openjdk.java.net] On Behalf Of >> Norman Maurer >> Sent: Montag, 2. Juli 2018 10:23 >> To: Baesken, Matthias >> Cc: Stuefe, Thomas ; net-dev at openjdk.java.net >> Subject: Re: RFR : 8205959 : Do not restart close if errno is EINTR >> >> +1 retry a close on EINTR has most likely not the outcome you expect and >> may even close a wrong FD if the same FD is reused already (as even if EINTR >> is returned it may have closed the FD) >> >>> Am 02.07.2018 um 10:17 schrieb Baesken, Matthias >> : >>> >>> Hello , there is a similar pattern (attempt to restart close in case of EINTR) >> in the coding as well in socket_md.c : >>> >>> src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c-147- int rv; >>> src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c-148- do { >>> src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c-149- rv = >> close(fd); >>> src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c:150: } while (rv >> == -1 && errno == EINTR); >>> src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c-151- >>> src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c-152- return rv; >>> src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c-153-} >>> >>> Do you think this needs adjustment (on LINUX) as well ? >>> >>> Best regards, Matthias >>> >>> >>>> Message: 2 >>>> Date: Thu, 28 Jun 2018 18:19:46 +0100 >>>> From: Alan Bateman >>>> To: David Lloyd , ivan.gerasimov at oracle.com >>>> Cc: OpenJDK Network Dev list >>>> Subject: Re: RFR : 8205959 : Do not restart close if errno is EINTR >>>> Message-ID: <3fd1496f-ab83-a2d5-0699-13c8b735d70b at oracle.com> >>>> Content-Type: text/plain; charset=utf-8; format=flowed >>>> >>>>> On 28/06/2018 17:35, David Lloyd wrote: >>>>> : >>>>> Do you (or Alan) think that this might have accounted for real-world >>>>> connection problems? >>>>> >>>> In the file I/O area, with NFS I think, we had an issue a long time ago >>>> where close was retried after EIO. That issue was fixed a long time ago >>>> but it's one that comes to mind in this general area. >>>> >>>> -Alan >>>> >>> From david.lloyd at redhat.com Mon Jul 2 13:43:06 2018 From: david.lloyd at redhat.com (David Lloyd) Date: Mon, 2 Jul 2018 08:43:06 -0500 Subject: RFR : 8205959 : Do not restart close if errno is EINTR In-Reply-To: <5a2ab4d2-ed90-20fd-6340-e73153d4313d@oracle.com> References: <2e9e20817ecf49d995cd2f939fefd774@sap.com> <2E0FD75E-3AEF-4251-B324-7F0BA864CFC2@googlemail.com> <9bf3ebbba0014f918bf53eb0b4d0c464@sap.com> <5a2ab4d2-ed90-20fd-6340-e73153d4313d@oracle.com> Message-ID: I think because the only two possible outcomes are either that the FD was not dup'd, in which case things carry on as before, or that it was dup'd, in which case (at least in the JVM) re-dupping won't really do anything harmful since the target FD already references the dead socket FD. The POSIX manpage doesn't seem to include any other possibilities. On Mon, Jul 2, 2018 at 7:04 AM David Holmes wrote: > > In reference to 8205959, where is it stated that dup2 is any more > restartable than close ?? > > AFAICS both leave things undefined/unspecified if they set EINTR. > > David > > On 2/07/2018 7:03 PM, Langer, Christoph wrote: > > Hi Matthias, > > > > forwarding to serviceability-dev, because debugging is usually discussed there. > > > > Yes, I would think this coding should be fixed, too. Can you open a bug and prepare a change? > > > > Thanks > > Christoph > > > >> -----Original Message----- > >> From: net-dev [mailto:net-dev-bounces at openjdk.java.net] On Behalf Of > >> Norman Maurer > >> Sent: Montag, 2. Juli 2018 10:23 > >> To: Baesken, Matthias > >> Cc: Stuefe, Thomas ; net-dev at openjdk.java.net > >> Subject: Re: RFR : 8205959 : Do not restart close if errno is EINTR > >> > >> +1 retry a close on EINTR has most likely not the outcome you expect and > >> may even close a wrong FD if the same FD is reused already (as even if EINTR > >> is returned it may have closed the FD) > >> > >>> Am 02.07.2018 um 10:17 schrieb Baesken, Matthias > >> : > >>> > >>> Hello , there is a similar pattern (attempt to restart close in case of EINTR) > >> in the coding as well in socket_md.c : > >>> > >>> src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c-147- int rv; > >>> src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c-148- do { > >>> src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c-149- rv = > >> close(fd); > >>> src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c:150: } while (rv > >> == -1 && errno == EINTR); > >>> src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c-151- > >>> src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c-152- return rv; > >>> src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c-153-} > >>> > >>> Do you think this needs adjustment (on LINUX) as well ? > >>> > >>> Best regards, Matthias > >>> > >>> > >>>> Message: 2 > >>>> Date: Thu, 28 Jun 2018 18:19:46 +0100 > >>>> From: Alan Bateman > >>>> To: David Lloyd , ivan.gerasimov at oracle.com > >>>> Cc: OpenJDK Network Dev list > >>>> Subject: Re: RFR : 8205959 : Do not restart close if errno is EINTR > >>>> Message-ID: <3fd1496f-ab83-a2d5-0699-13c8b735d70b at oracle.com> > >>>> Content-Type: text/plain; charset=utf-8; format=flowed > >>>> > >>>>> On 28/06/2018 17:35, David Lloyd wrote: > >>>>> : > >>>>> Do you (or Alan) think that this might have accounted for real-world > >>>>> connection problems? > >>>>> > >>>> In the file I/O area, with NFS I think, we had an issue a long time ago > >>>> where close was retried after EIO. That issue was fixed a long time ago > >>>> but it's one that comes to mind in this general area. > >>>> > >>>> -Alan > >>>> > >>> -- - DML From matthias.baesken at sap.com Mon Jul 2 13:44:22 2018 From: matthias.baesken at sap.com (Baesken, Matthias) Date: Mon, 2 Jul 2018 13:44:22 +0000 Subject: 8206145 : dbgsysSocketClose - do not restart close if errno is EINTR [linux] - was : RE: RFR : 8205959 : Do not restart close if errno is EINTR Message-ID: <228035d2f64c494eaefe31b07ac72083@sap.com> I created a bug and a webrev , please review . https://bugs.openjdk.java.net/browse/JDK-8206145 http://cr.openjdk.java.net/~mbaesken/webrevs/8206145/ ( The other bug where a similar issue was addressed is https://bugs.openjdk.java.net/browse/JDK-8205959 ) Best regards, Matthias > -----Original Message----- > From: Thomas St?fe [mailto:thomas.stuefe at gmail.com] > Sent: Montag, 2. Juli 2018 12:08 > To: Baesken, Matthias ; Langer, Christoph > > Cc: serviceability-dev (serviceability-dev at openjdk.java.net) dev at openjdk.java.net>; Stuefe, Thomas ; net- > dev at openjdk.java.net > Subject: Re: RFR : 8205959 : Do not restart close if errno is EINTR > > +1. Please fix this for Linux! Thanks. > > On Mon, Jul 2, 2018 at 11:03 AM, Langer, Christoph > wrote: > > Hi Matthias, > > > > forwarding to serviceability-dev, because debugging is usually discussed > there. > > > > Yes, I would think this coding should be fixed, too. Can you open a bug and > prepare a change? > > > > Thanks > > Christoph > > > >> -----Original Message----- > >> From: net-dev [mailto:net-dev-bounces at openjdk.java.net] On Behalf Of > >> Norman Maurer > >> Sent: Montag, 2. Juli 2018 10:23 > >> To: Baesken, Matthias > >> Cc: Stuefe, Thomas ; net- > dev at openjdk.java.net > >> Subject: Re: RFR : 8205959 : Do not restart close if errno is EINTR > >> > >> +1 retry a close on EINTR has most likely not the outcome you expect and > >> may even close a wrong FD if the same FD is reused already (as even if > EINTR > >> is returned it may have closed the FD) > >> > >> > Am 02.07.2018 um 10:17 schrieb Baesken, Matthias > >> : > >> > > >> > Hello , there is a similar pattern (attempt to restart close in case of > EINTR) > >> in the coding as well in socket_md.c : > >> > > >> > src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c-147- int rv; > >> > src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c-148- do { > >> > src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c-149- rv = > >> close(fd); > >> > src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c:150: } while > (rv > >> == -1 && errno == EINTR); > >> > src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c-151- > >> > src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c-152- return > rv; > >> > src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c-153-} > >> > > >> > Do you think this needs adjustment (on LINUX) as well ? > >> > > >> > Best regards, Matthias > >> > > >> > > >> >> Message: 2 > >> >> Date: Thu, 28 Jun 2018 18:19:46 +0100 > >> >> From: Alan Bateman > >> >> To: David Lloyd , > ivan.gerasimov at oracle.com > >> >> Cc: OpenJDK Network Dev list > >> >> Subject: Re: RFR : 8205959 : Do not restart close if errno is EINTR > >> >> Message-ID: <3fd1496f-ab83-a2d5-0699-13c8b735d70b at oracle.com> > >> >> Content-Type: text/plain; charset=utf-8; format=flowed > >> >> > >> >>> On 28/06/2018 17:35, David Lloyd wrote: > >> >>> : > >> >>> Do you (or Alan) think that this might have accounted for real-world > >> >>> connection problems? > >> >>> > >> >> In the file I/O area, with NFS I think, we had an issue a long time ago > >> >> where close was retried after EIO. That issue was fixed a long time ago > >> >> but it's one that comes to mind in this general area. > >> >> > >> >> -Alan > >> >> > >> > From brian.burkhalter at oracle.com Mon Jul 2 17:21:31 2018 From: brian.burkhalter at oracle.com (Brian Burkhalter) Date: Mon, 2 Jul 2018 10:21:31 -0700 Subject: [12] 8194899: Remove unused sun.net classes Message-ID: <4A389D36-0536-4A34-9B59-8ED4706DD227@oracle.com> https://bugs.openjdk.java.net/browse/JDK-8194899 The proposed change is to remove these classes which are unused in the JDK: sun.net.NetworkServer sun.net.URLCanonicalizer Thanks, Brian From Alan.Bateman at oracle.com Mon Jul 2 17:23:17 2018 From: Alan.Bateman at oracle.com (Alan Bateman) Date: Mon, 2 Jul 2018 18:23:17 +0100 Subject: [12] 8194899: Remove unused sun.net classes In-Reply-To: <4A389D36-0536-4A34-9B59-8ED4706DD227@oracle.com> References: <4A389D36-0536-4A34-9B59-8ED4706DD227@oracle.com> Message-ID: On 02/07/2018 18:21, Brian Burkhalter wrote: > https://bugs.openjdk.java.net/browse/JDK-8194899 > > The proposed change is to remove these classes which are unused in the JDK: > > sun.net.NetworkServer > sun.net.URLCanonicalizer > Should be okay, assuming the JDK builds and there aren't any tests using it. -Alan From brian.burkhalter at oracle.com Mon Jul 2 17:31:45 2018 From: brian.burkhalter at oracle.com (Brian Burkhalter) Date: Mon, 2 Jul 2018 10:31:45 -0700 Subject: [12] 8194899: Remove unused sun.net classes In-Reply-To: References: <4A389D36-0536-4A34-9B59-8ED4706DD227@oracle.com> Message-ID: <07016D10-2C24-465D-8A3B-30ECDE939ECC@oracle.com> On Jul 2, 2018, at 10:23 AM, Alan Bateman wrote: > On 02/07/2018 18:21, Brian Burkhalter wrote: >> https://bugs.openjdk.java.net/browse/JDK-8194899 >> >> The proposed change is to remove these classes which are unused in the JDK: >> >> sun.net.NetworkServer >> sun.net.URLCanonicalizer >> > Should be okay, assuming the JDK builds and there aren't any tests using it. It was fine before the 12 fork but I am going to rebuild and re-run the tests again to be sure. Thanks, Brian -------------- next part -------------- An HTML attachment was scrubbed... URL: From michael.x.mcmahon at oracle.com Wed Jul 4 09:31:24 2018 From: michael.x.mcmahon at oracle.com (Michael McMahon) Date: Wed, 04 Jul 2018 10:31:24 +0100 Subject: RFR (11): 8206001 Enable TLS1.3 by default in Http Client Message-ID: <5B3C93EC.8070208@oracle.com> Hi, Can I get the following change reviewed please for 11? It is to enable the use of TLS1.3 in the http client by default plus associated changes caused by the new implementation. http://cr.openjdk.java.net/~michaelm/8206001/webrev.01/ Thanks, Michael. From daniel.fuchs at oracle.com Wed Jul 4 15:02:13 2018 From: daniel.fuchs at oracle.com (Daniel Fuchs) Date: Wed, 4 Jul 2018 17:02:13 +0200 Subject: RFR (11): 8206001 Enable TLS1.3 by default in Http Client In-Reply-To: <5B3C93EC.8070208@oracle.com> References: <5B3C93EC.8070208@oracle.com> Message-ID: <01856a72-f72b-8868-afff-9bbfc522d774@oracle.com> Hi Michael, This looks good to me. I have tested this changeset both on jdk/jdk11 and jdk/jdk and all my results are green. I also ran tier1, tier2 and tier3 tests on jdk11. I'm glad to see that the rare intermittent failures I was seeing before this patch have now disappeared from my tests results. best regards, -- daniel On 04/07/2018 11:31, Michael McMahon wrote: > Hi, > > Can I get the following change reviewed please for 11? > > It is to enable the use of TLS1.3 in the http client by default > plus associated changes caused by the new implementation. > > http://cr.openjdk.java.net/~michaelm/8206001/webrev.01/ > > Thanks, > > Michael. From andrewluotechnologies at outlook.com Tue Jul 10 08:36:28 2018 From: andrewluotechnologies at outlook.com (Andrew Luo) Date: Tue, 10 Jul 2018 08:36:28 +0000 Subject: [PATCH] SOCK_CLOEXEC for opening sockets Message-ID: Hi, I want to propose to use SOCK_CLOEXEC when opening sockets in the OpenJDK. I ran into some issues when forking processes (in JNI/C/C++/native code) on Linux where OpenJDK had opened a socket (in Java code). The child process ends up inheriting a file descriptor to the same socket, which is not ideal in certain circumstances (for example if the Java process restarts and tries to open the socket again while the child process is still running). Of course, after forking the child process can close all those file descriptors as a workaround, but we use O_CLOEXEC when opening files, so I think it would be ideal to use the same for sockets. Just some info about the patch: 1. This is only for Linux (I don't believe SOCK_CLOEXEC exists on other platforms, I use a preprocessor guard for SOCK_CLOEXEC) 2. I try twice if the first time attempting to open the socket fails with EINVAL because it is possible that the OpenJDK was compiled on a newer kernel/with newer headers that supports SOCK_CLOEXEC but runs on a lower version kernel (not sure if this is supported by the OpenJDK project) Patch is attached below. Let me know if you want me to make some changes. (I did not add a unit test - it would probably need to be a functional test, one that involves a child process and forking, etc. Let me know if you believe this is necessary to add) Thanks, -Andrew diff -r 95c0644a1c47 src/java.base/unix/native/libnet/PlainSocketImpl.c --- a/src/java.base/unix/native/libnet/PlainSocketImpl.c Fri Jun 15 17:34:01 2018 -0700 +++ b/src/java.base/unix/native/libnet/PlainSocketImpl.c Tue Jul 10 01:30:08 2018 -0700 @@ -104,6 +104,34 @@ } /* + * Opens a socket + * On systems where supported, uses SOCK_CLOEXEC where possible + */ +static int openSocket(int domain, int type, int protocol) { +#if defined(SOCK_CLOEXEC) + int typeToUse = type | SOCK_CLOEXEC; +#else + int typeToUse = type; +#endif + + int socketFileDescriptor = socket(domain, typeToUse, protocol); +#if defined(SOCK_CLOEXEC) + if ((socketFileDescriptor == -1) && (errno = EINVAL)) { + // Attempt to open the socket without SOCK_CLOEXEC + // May have been compiled on an OS with SOCK_CLOEXEC supported + // But runtime system might not have SOCK_CLOEXEC support + socketFileDescriptor = socket(domain, type, protocol); + } +#else + // Best effort + // Return value is intentionally ignored since socket was successfully opened anyways + fcntl(socketFileDescriptor, F_SETFD, FD_CLOEXEC); +#endif + + return socketFileDescriptor; +} + +/* * The initroto function is called whenever PlainSocketImpl is * loaded, to cache field IDs for efficiency. This is called every time * the Java class is loaded. @@ -178,7 +206,8 @@ return; } - if ((fd = socket(domain, type, 0)) == -1) { + + if ((fd = openSocket(domain, type, 0)) == -1) { /* note: if you run out of fds, you may not be able to load * the exception class, and get a NoClassDefFoundError * instead. -------------- next part -------------- An HTML attachment was scrubbed... URL: From martinrb at google.com Tue Jul 10 16:40:58 2018 From: martinrb at google.com (Martin Buchholz) Date: Tue, 10 Jul 2018 09:40:58 -0700 Subject: [PATCH] SOCK_CLOEXEC for opening sockets In-Reply-To: References: Message-ID: I agree with this approach - it parallels the efforts made with O_CLOEXEC in past years. According to https://www.freebsd.org/cgi/man.cgi?query=socket&sektion=2 SOCK_CLOEXEC is also available on freebsd. On Tue, Jul 10, 2018 at 1:36 AM, Andrew Luo < andrewluotechnologies at outlook.com> wrote: > Hi, > > > > I want to propose to use SOCK_CLOEXEC when opening sockets in the > OpenJDK. I ran into some issues when forking processes (in > JNI/C/C++/native code) on Linux where OpenJDK had opened a socket (in Java > code). The child process ends up inheriting a file descriptor to the same > socket, which is not ideal in certain circumstances (for example if the > Java process restarts and tries to open the socket again while the child > process is still running). Of course, after forking the child process can > close all those file descriptors as a workaround, but we use O_CLOEXEC when > opening files, so I think it would be ideal to use the same for sockets. > > > > Just some info about the patch: > > > > 1. This is only for Linux (I don?t believe SOCK_CLOEXEC exists on > other platforms, I use a preprocessor guard for SOCK_CLOEXEC) > > 2. I try twice if the first time attempting to open the socket > fails with EINVAL because it is possible that the OpenJDK was compiled on a > newer kernel/with newer headers that supports SOCK_CLOEXEC but runs on a > lower version kernel (not sure if this is supported by the OpenJDK project) > > > > Patch is attached below. Let me know if you want me to make some changes. > > > > (I did not add a unit test ? it would probably need to be a functional > test, one that involves a child process and forking, etc. Let me know if > you believe this is necessary to add) > > > > Thanks, > > > > -Andrew > > > > diff -r 95c0644a1c47 src/java.base/unix/native/libnet/PlainSocketImpl.c > > --- a/src/java.base/unix/native/libnet/PlainSocketImpl.c Fri Jun 15 > 17:34:01 2018 -0700 > > +++ b/src/java.base/unix/native/libnet/PlainSocketImpl.c Tue > Jul 10 01:30:08 2018 -0700 > > @@ -104,6 +104,34 @@ > > } > > /* > > + * Opens a socket > > + * On systems where supported, uses SOCK_CLOEXEC where possible > > + */ > > +static int openSocket(int domain, int type, int protocol) { > > +#if defined(SOCK_CLOEXEC) > > + int typeToUse = type | SOCK_CLOEXEC; > > +#else > > + int typeToUse = type; > > +#endif > > + > > + int socketFileDescriptor = socket(domain, typeToUse, protocol); > > +#if defined(SOCK_CLOEXEC) > > + if ((socketFileDescriptor == -1) && (errno = EINVAL)) { > > + // Attempt to open the socket without SOCK_CLOEXEC > > + // May have been compiled on an OS with SOCK_CLOEXEC supported > > + // But runtime system might not have SOCK_CLOEXEC support > > + socketFileDescriptor = socket(domain, type, protocol); > > + } > > +#else > > + // Best effort > > + // Return value is intentionally ignored since socket was > successfully opened anyways > > + fcntl(socketFileDescriptor, F_SETFD, FD_CLOEXEC); > > +#endif > > + > > + return socketFileDescriptor; > > +} > > + > > +/* > > * The initroto function is called whenever PlainSocketImpl is > > * loaded, to cache field IDs for efficiency. This is called every time > > * the Java class is loaded. > > @@ -178,7 +206,8 @@ > > return; > > } > > - if ((fd = socket(domain, type, 0)) == -1) { > > + > > + if ((fd = openSocket(domain, type, 0)) == -1) { > > /* note: if you run out of fds, you may not be able to load > > * the exception class, and get a NoClassDefFoundError > > * instead. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From norman.maurer at googlemail.com Tue Jul 10 16:47:35 2018 From: norman.maurer at googlemail.com (Norman Maurer) Date: Tue, 10 Jul 2018 17:47:35 +0100 Subject: Unable to use custom SSLEngine with default TrustManagerFactory after updating to ea20 (and later) Message-ID: Hi all, I just tried to run netty[1] testsuite with the latest jdk11 EA release (21) and saw some class-cast-exception with our custom SSLEngine implementation Caused by: java.lang.ClassCastException: class io.netty.handler.ssl.OpenSslEngine cannot be cast to class sun.security.ssl.SSLEngineImpl (io.netty.handler.ssl.OpenSslEngine is in unnamed module of loader 'app'; sun.security.ssl.SSLEngineImpl is in module java.base of loader 'bootstrap') at java.base/sun.security.ssl.SSLAlgorithmConstraints.(SSLAlgorithmConstraints.java:93) at java.base/sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:270) at java.base/sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:141) at io.netty.handler.ssl.ReferenceCountedOpenSslClientContext$ExtendedTrustManagerVerifyCallback.verify(ReferenceCountedOpenSslClientContext.java:237) at io.netty.handler.ssl.ReferenceCountedOpenSslContext$AbstractCertificateVerifier.verify(ReferenceCountedOpenSslContext.java:621) ... 27 more This change seems to be related to: http://hg.openjdk.java.net/jdk/jdk11/rev/68fa3d4026ea I think you miss an instanceof check here in SSLAlgorithmConstraints before try to cast to SSLEngineImpl, as otherwise it will be impossible to use custom implementations of SSLEngine (which we have in netty) with the default TrustManagerFactory. Does this sound correct ? Should I open a bug-report ? Bye Norman -------------- next part -------------- An HTML attachment was scrubbed... URL: From Alan.Bateman at oracle.com Tue Jul 10 16:54:26 2018 From: Alan.Bateman at oracle.com (Alan Bateman) Date: Tue, 10 Jul 2018 17:54:26 +0100 Subject: [PATCH] SOCK_CLOEXEC for opening sockets In-Reply-To: References: Message-ID: <0c24795d-350e-3ac8-4417-0480b41c5c9c@oracle.com> On 10/07/2018 17:40, Martin Buchholz wrote: > I agree with this approach - it parallels the efforts made with > O_CLOEXEC in past years. > > According to > https://www.freebsd.org/cgi/man.cgi?query=socket&sektion=2 > SOCK_CLOEXEC is also available on freebsd. > This is something that doesn't come up too often, I assume because most developers using ProcessBuilder/Process rather than invoking fork from native code. If we are going to tackle this issue then it will require changes in several places, changing PlainSocketImpl.c is just one of several. -Alan -------------- next part -------------- An HTML attachment was scrubbed... URL: From norman.maurer at googlemail.com Tue Jul 10 16:55:18 2018 From: norman.maurer at googlemail.com (Norman Maurer) Date: Tue, 10 Jul 2018 17:55:18 +0100 Subject: [PATCH] SOCK_CLOEXEC for opening sockets In-Reply-To: <0c24795d-350e-3ac8-4417-0480b41c5c9c@oracle.com> References: <0c24795d-350e-3ac8-4417-0480b41c5c9c@oracle.com> Message-ID: +1 I think this makes a lot of sense > On 10. Jul 2018, at 17:54, Alan Bateman wrote: > > On 10/07/2018 17:40, Martin Buchholz wrote: >> I agree with this approach - it parallels the efforts made with O_CLOEXEC in past years. >> >> According to >> https://www.freebsd.org/cgi/man.cgi?query=socket&sektion=2 >> SOCK_CLOEXEC is also available on freebsd. >> > This is something that doesn't come up too often, I assume because most developers using ProcessBuilder/Process rather than invoking fork from native code. > > If we are going to tackle this issue then it will require changes in several places, changing PlainSocketImpl.c is just one of several. > > -Alan -------------- next part -------------- An HTML attachment was scrubbed... URL: From andrewluotechnologies at outlook.com Wed Jul 11 06:35:38 2018 From: andrewluotechnologies at outlook.com (Andrew Luo) Date: Wed, 11 Jul 2018 06:35:38 +0000 Subject: [PATCH] SOCK_CLOEXEC for opening sockets In-Reply-To: References: <0c24795d-350e-3ac8-4417-0480b41c5c9c@oracle.com> Message-ID: I agree, I wasn't aware of the other uses of ::socket in the libnet codebase. Thus, I've added a new common function, NET_SocketOpen that can be used by all the source files in libnet and revised my patch: diff -r 95c0644a1c47 src/java.base/unix/native/libnet/Inet4AddressImpl.c --- a/src/java.base/unix/native/libnet/Inet4AddressImpl.c Fri Jun 15 17:34:01 2018 -0700 +++ b/src/java.base/unix/native/libnet/Inet4AddressImpl.c Tue Jul 10 23:32:21 2018 -0700 @@ -264,7 +264,7 @@ int connect_rv = -1; // open a TCP socket - fd = socket(AF_INET, SOCK_STREAM, 0); + fd = NET_SocketOpen(AF_INET, SOCK_STREAM, 0); if (fd == -1) { // note: if you run out of fds, you may not be able to load // the exception class, and get a NoClassDefFoundError instead. @@ -503,7 +503,7 @@ // Let's try to create a RAW socket to send ICMP packets. // This usually requires "root" privileges, so it's likely to fail. - fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); + fd = NET_SocketOpen(AF_INET, SOCK_RAW, IPPROTO_ICMP); if (fd == -1) { return tcp_ping4(env, &sa, netif, timeout, ttl); } else { diff -r 95c0644a1c47 src/java.base/unix/native/libnet/Inet6AddressImpl.c --- a/src/java.base/unix/native/libnet/Inet6AddressImpl.c Fri Jun 15 17:34:01 2018 -0700 +++ b/src/java.base/unix/native/libnet/Inet6AddressImpl.c Tue Jul 10 23:32:21 2018 -0700 @@ -461,7 +461,7 @@ int connect_rv = -1; // open a TCP socket - fd = socket(AF_INET6, SOCK_STREAM, 0); + fd = NET_SocketOpen(AF_INET6, SOCK_STREAM, 0); if (fd == -1) { // note: if you run out of fds, you may not be able to load // the exception class, and get a NoClassDefFoundError instead. @@ -711,7 +711,7 @@ // Let's try to create a RAW socket to send ICMP packets. // This usually requires "root" privileges, so it's likely to fail. - fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); + fd = NET_SocketOpen(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); if (fd == -1) { return tcp_ping6(env, &sa, netif, timeout, ttl); } else { diff -r 95c0644a1c47 src/java.base/unix/native/libnet/NetworkInterface.c --- a/src/java.base/unix/native/libnet/NetworkInterface.c Fri Jun 15 17:34:01 2018 -0700 +++ b/src/java.base/unix/native/libnet/NetworkInterface.c Tue Jul 10 23:32:21 2018 -0700 @@ -1055,7 +1055,7 @@ static int openSocket(JNIEnv *env, int proto) { int sock; - if ((sock = socket(proto, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_SocketOpen(proto, SOCK_DGRAM, 0)) < 0) { // If EPROTONOSUPPORT is returned it means we don't have // support for this proto so don't throw an exception. if (errno != EPROTONOSUPPORT) { @@ -1078,9 +1078,9 @@ static int openSocketWithFallback(JNIEnv *env, const char *ifname) { int sock; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_SocketOpen(AF_INET, SOCK_DGRAM, 0)) < 0) { if (errno == EPROTONOSUPPORT) { - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_SocketOpen(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; @@ -1315,9 +1315,9 @@ static int openSocketWithFallback(JNIEnv *env, const char *ifname) { int sock; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_SocketOpen(AF_INET, SOCK_DGRAM, 0)) < 0) { if (errno == EPROTONOSUPPORT) { - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_SocketOpen(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; @@ -1590,9 +1590,9 @@ int sock, alreadyV6 = 0; struct lifreq if2; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_SocketOpen(AF_INET, SOCK_DGRAM, 0)) < 0) { if (errno == EPROTONOSUPPORT) { - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_SocketOpen(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; @@ -1616,7 +1616,7 @@ strncpy(if2.lifr_name, ifname, sizeof(if2.lifr_name) - 1); if (ioctl(sock, SIOCGLIFNETMASK, (char *)&if2) < 0) { close(sock); - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_SocketOpen(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; @@ -1941,9 +1941,9 @@ static int openSocketWithFallback(JNIEnv *env, const char *ifname) { int sock; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_SocketOpen(AF_INET, SOCK_DGRAM, 0)) < 0) { if (errno == EPROTONOSUPPORT) { - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_SocketOpen(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; diff -r 95c0644a1c47 src/java.base/unix/native/libnet/PlainSocketImpl.c --- a/src/java.base/unix/native/libnet/PlainSocketImpl.c Fri Jun 15 17:34:01 2018 -0700 +++ b/src/java.base/unix/native/libnet/PlainSocketImpl.c Tue Jul 10 23:32:21 2018 -0700 @@ -178,7 +178,7 @@ return; } - if ((fd = socket(domain, type, 0)) == -1) { + if ((fd = NET_SocketOpen(domain, type, 0)) == -1) { /* note: if you run out of fds, you may not be able to load * the exception class, and get a NoClassDefFoundError * instead. diff -r 95c0644a1c47 src/java.base/unix/native/libnet/SdpSupport.c --- a/src/java.base/unix/native/libnet/SdpSupport.c Fri Jun 15 17:34:01 2018 -0700 +++ b/src/java.base/unix/native/libnet/SdpSupport.c Tue Jul 10 23:32:21 2018 -0700 @@ -57,7 +57,7 @@ #if defined(__solaris__) int domain = ipv6_available() ? AF_INET6 : AF_INET; - s = socket(domain, SOCK_STREAM, PROTO_SDP); + s = NET_SocketOpen(domain, SOCK_STREAM, PROTO_SDP); #elif defined(__linux__) /** * IPv6 not supported by SDP on Linux @@ -66,7 +66,7 @@ JNU_ThrowIOException(env, "IPv6 not supported"); return -1; } - s = socket(AF_INET_SDP, SOCK_STREAM, 0); + s = NET_SocketOpen(AF_INET_SDP, SOCK_STREAM, 0); #else /* not supported on other platforms at this time */ s = -1; diff -r 95c0644a1c47 src/java.base/unix/native/libnet/net_util_md.c --- a/src/java.base/unix/native/libnet/net_util_md.c Fri Jun 15 17:34:01 2018 -0700 +++ b/src/java.base/unix/native/libnet/net_util_md.c Tue Jul 10 23:32:21 2018 -0700 @@ -117,6 +117,34 @@ return defaultIndex; } +/* + * Opens a socket + * On systems where supported, uses SOCK_CLOEXEC where possible + */ +int NET_SocketOpen(int domain, int type, int protocol) { +#if defined(SOCK_CLOEXEC) + int typeToUse = type | SOCK_CLOEXEC; +#else + int typeToUse = type; +#endif + + int socketFileDescriptor = socket(domain, typeToUse, protocol); +#if defined(SOCK_CLOEXEC) + if ((socketFileDescriptor == -1) && (errno = EINVAL)) { + // Attempt to open the socket without SOCK_CLOEXEC + // May have been compiled on an OS with SOCK_CLOEXEC supported + // But runtime system might not have SOCK_CLOEXEC support + socketFileDescriptor = socket(domain, type, protocol); + } +#else + // Best effort + // Return value is intentionally ignored since socket was successfully opened anyways + fcntl(socketFileDescriptor, F_SETFD, FD_CLOEXEC); +#endif + + return socketFileDescriptor; +} + #define RESTARTABLE(_cmd, _result) do { \ do { \ _result = _cmd; \ @@ -295,7 +323,7 @@ SOCKETADDRESS sa; socklen_t sa_len = sizeof(SOCKETADDRESS); - fd = socket(AF_INET6, SOCK_STREAM, 0) ; + fd = NET_SocketOpen(AF_INET6, SOCK_STREAM, 0) ; if (fd < 0) { /* * TODO: We really cant tell since it may be an unrelated error @@ -402,7 +430,7 @@ /* Do a simple dummy call, and try to figure out from that */ int one = 1; int rv, s; - s = socket(PF_INET, SOCK_STREAM, 0); + s = NET_SocketOpen(PF_INET, SOCK_STREAM, 0); if (s < 0) { return JNI_FALSE; } diff -r 95c0644a1c47 src/java.base/unix/native/libnet/net_util_md.h --- a/src/java.base/unix/native/libnet/net_util_md.h Fri Jun 15 17:34:01 2018 -0700 +++ b/src/java.base/unix/native/libnet/net_util_md.h Tue Jul 10 23:32:21 2018 -0700 @@ -89,6 +89,7 @@ int NET_Writev(int s, const struct iovec * vector, int count); int NET_Connect(int s, struct sockaddr *addr, int addrlen); int NET_Accept(int s, struct sockaddr *addr, socklen_t *addrlen); +int NET_SocketOpen(int domain, int type, int protocol); int NET_SocketClose(int s); int NET_Dup2(int oldfd, int newfd); int NET_Poll(struct pollfd *ufds, unsigned int nfds, int timeout); From: Norman Maurer Sent: Tuesday, July 10, 2018 9:55 AM To: Alan Bateman Cc: Martin Buchholz ; Andrew Luo ; net-dev at openjdk.java.net Subject: Re: [PATCH] SOCK_CLOEXEC for opening sockets +1 I think this makes a lot of sense On 10. Jul 2018, at 17:54, Alan Bateman > wrote: On 10/07/2018 17:40, Martin Buchholz wrote: I agree with this approach - it parallels the efforts made with O_CLOEXEC in past years. According to https://www.freebsd.org/cgi/man.cgi?query=socket&sektion=2 SOCK_CLOEXEC is also available on freebsd. This is something that doesn't come up too often, I assume because most developers using ProcessBuilder/Process rather than invoking fork from native code. If we are going to tackle this issue then it will require changes in several places, changing PlainSocketImpl.c is just one of several. -Alan -------------- next part -------------- An HTML attachment was scrubbed... URL: From Alan.Bateman at oracle.com Wed Jul 11 07:11:48 2018 From: Alan.Bateman at oracle.com (Alan Bateman) Date: Wed, 11 Jul 2018 08:11:48 +0100 Subject: [PATCH] SOCK_CLOEXEC for opening sockets In-Reply-To: References: <0c24795d-350e-3ac8-4417-0480b41c5c9c@oracle.com> Message-ID: This seems to cover the sockets created in libnet but there is also a usage in libnio that will need update. It might be cleaner to name it NET_Socket to be consistent with the other wrappers (NET_Bind, NET_SetSocketOpt, etc.). There are a lot of other file descriptors that you may run into. We use socketpair in a few places, we have file descriptors for epoll and more. It makes me wonder if it would be better to use FD_CLOEXEC consistently. In the Windows port then you'll see that we change the inheritance flag on all newly created SOCKETs, that is because is because we don't have the same opportunity to close inherited handles in the child process that we do on Unix platforms. -Alan On 11/07/2018 07:35, Andrew Luo wrote: > > I agree, I wasn?t aware of the other uses of ::socket in the libnet > codebase.? Thus, I?ve added a new common function, NET_SocketOpen that > can be used by all the source files in libnet and revised my patch: > > diff -r 95c0644a1c47 src/java.base/unix/native/libnet/Inet4AddressImpl.c > > --- a/src/java.base/unix/native/libnet/Inet4AddressImpl.c???????????? > Fri Jun 15 17:34:01 2018 -0700 > > +++ b/src/java.base/unix/native/libnet/Inet4AddressImpl.c????????? Tue > Jul 10 23:32:21 2018 -0700 > > @@ -264,7 +264,7 @@ > > ?int connect_rv = -1; > > ?????// open a TCP socket > > - fd = socket(AF_INET, SOCK_STREAM, 0); > > + fd = NET_SocketOpen(AF_INET, SOCK_STREAM, 0); > > if (fd == -1) { > > // note: if you run out of fds, you may not be able to load > > // the exception class, and get a NoClassDefFoundError instead. > > @@ -503,7 +503,7 @@ > > ?????// Let's try to create a RAW socket to send ICMP packets. > > // This usually requires "root" privileges, so it's likely to fail. > > - fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); > > + fd = NET_SocketOpen(AF_INET, SOCK_RAW, IPPROTO_ICMP); > > if (fd == -1) { > > return tcp_ping4(env, &sa, netif, timeout, ttl); > > } else { > > diff -r 95c0644a1c47 src/java.base/unix/native/libnet/Inet6AddressImpl.c > > --- a/src/java.base/unix/native/libnet/Inet6AddressImpl.c???????????? > Fri Jun 15 17:34:01 2018 -0700 > > +++ b/src/java.base/unix/native/libnet/Inet6AddressImpl.c????????? Tue > Jul 10 23:32:21 2018 -0700 > > @@ -461,7 +461,7 @@ > > int connect_rv = -1; > > ?????// open a TCP socket > > - ?fd = socket(AF_INET6, SOCK_STREAM, 0); > > + fd = NET_SocketOpen(AF_INET6, SOCK_STREAM, 0); > > if (fd == -1) { > > // note: if you run out of fds, you may not be able to load > > // the exception class, and get a NoClassDefFoundError instead. > > @@ -711,7 +711,7 @@ > > ?????// Let's try to create a RAW socket to send ICMP packets. > > // This usually requires "root" privileges, so it's likely to fail. > > - fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); > > + fd = NET_SocketOpen(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); > > if (fd == -1) { > > return tcp_ping6(env, &sa, netif, timeout, ttl); > > } else { > > diff -r 95c0644a1c47 src/java.base/unix/native/libnet/NetworkInterface.c > > --- a/src/java.base/unix/native/libnet/NetworkInterface.c???????????? > Fri Jun 15 17:34:01 2018 -0700 > > +++ b/src/java.base/unix/native/libnet/NetworkInterface.c????????? Tue > Jul 10 23:32:21 2018 -0700 > > @@ -1055,7 +1055,7 @@ > > static int openSocket(JNIEnv *env, int proto) { > > int sock; > > - if ((sock = socket(proto, SOCK_DGRAM, 0)) < 0) { > > + if ((sock = NET_SocketOpen(proto, SOCK_DGRAM, 0)) < 0) { > > // If EPROTONOSUPPORT is returned it means we don't have > > // support for this proto so don't throw an exception. > > if (errno != EPROTONOSUPPORT) { > > @@ -1078,9 +1078,9 @@ > > static int openSocketWithFallback(JNIEnv *env, const char *ifname) { > > int sock; > > - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { > > + if ((sock = NET_SocketOpen(AF_INET, SOCK_DGRAM, 0)) < 0) { > > if (errno == EPROTONOSUPPORT) { > > - ????if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { > > + if ((sock = NET_SocketOpen(AF_INET6, SOCK_DGRAM, 0)) < 0) { > > JNU_ThrowByNameWithMessageAndLastError > > (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); > > return -1; > > @@ -1315,9 +1315,9 @@ > > static int openSocketWithFallback(JNIEnv *env, const char *ifname) { > > int sock; > > - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { > > + if ((sock = NET_SocketOpen(AF_INET, SOCK_DGRAM, 0)) < 0) { > > if (errno == EPROTONOSUPPORT) { > > - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { > > + if ((sock = NET_SocketOpen(AF_INET6, SOCK_DGRAM, 0)) < 0) { > > JNU_ThrowByNameWithMessageAndLastError > > (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); > > return -1; > > @@ -1590,9 +1590,9 @@ > > int sock, alreadyV6 = 0; > > struct lifreq if2; > > - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { > > + if ((sock = NET_SocketOpen(AF_INET, SOCK_DGRAM, 0)) < 0) { > > if (errno == EPROTONOSUPPORT) { > > - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { > > + if ((sock = NET_SocketOpen(AF_INET6, SOCK_DGRAM, 0)) < 0) { > > JNU_ThrowByNameWithMessageAndLastError > > (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); > > return -1; > > @@ -1616,7 +1616,7 @@ > > strncpy(if2.lifr_name, ifname, sizeof(if2.lifr_name) - 1); > > if (ioctl(sock, SIOCGLIFNETMASK, (char *)&if2) < 0) { > > close(sock); > > - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { > > + if ((sock = NET_SocketOpen(AF_INET6, SOCK_DGRAM, 0)) < 0) { > > JNU_ThrowByNameWithMessageAndLastError > > (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); > > return -1; > > @@ -1941,9 +1941,9 @@ > > static int openSocketWithFallback(JNIEnv *env, const char *ifname) { > > int sock; > > - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { > > + if ((sock = NET_SocketOpen(AF_INET, SOCK_DGRAM, 0)) < 0) { > > if (errno == EPROTONOSUPPORT) { > > - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { > > + if ((sock = NET_SocketOpen(AF_INET6, SOCK_DGRAM, 0)) < 0) { > > JNU_ThrowByNameWithMessageAndLastError > > (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); > > return -1; > > diff -r 95c0644a1c47 src/java.base/unix/native/libnet/PlainSocketImpl.c > > --- a/src/java.base/unix/native/libnet/PlainSocketImpl.c Fri Jun 15 > 17:34:01 2018 -0700 > > +++ b/src/java.base/unix/native/libnet/PlainSocketImpl.c???????????? > Tue Jul 10 23:32:21 2018 -0700 > > @@ -178,7 +178,7 @@ > > return; > > } > > - if ((fd = socket(domain, type, 0)) == -1) { > > + if ((fd = NET_SocketOpen(domain, type, 0)) == -1) { > > /* note: if you run out of fds, you may not be able to load > > * the exception class, and get a NoClassDefFoundError > > * instead. > > diff -r 95c0644a1c47 src/java.base/unix/native/libnet/SdpSupport.c > > --- a/src/java.base/unix/native/libnet/SdpSupport.c???????? Fri Jun 15 > 17:34:01 2018 -0700 > > +++ b/src/java.base/unix/native/libnet/SdpSupport.c????? Tue Jul 10 > 23:32:21 2018 -0700 > > @@ -57,7 +57,7 @@ > > ?#if defined(__solaris__) > > int domain = ipv6_available() ? AF_INET6 : AF_INET; > > - s = socket(domain, SOCK_STREAM, PROTO_SDP); > > + s = NET_SocketOpen(domain, SOCK_STREAM, PROTO_SDP); > > #elif defined(__linux__) > > /** > > * IPv6 not supported by SDP on Linux > > @@ -66,7 +66,7 @@ > > JNU_ThrowIOException(env, "IPv6 not supported"); > > return -1; > > } > > - s = socket(AF_INET_SDP, SOCK_STREAM, 0); > > + s = NET_SocketOpen(AF_INET_SDP, SOCK_STREAM, 0); > > #else > > /* not supported on other platforms at this time */ > > s = -1; > > diff -r 95c0644a1c47 src/java.base/unix/native/libnet/net_util_md.c > > --- a/src/java.base/unix/native/libnet/net_util_md.c?????? Fri Jun 15 > 17:34:01 2018 -0700 > > +++ b/src/java.base/unix/native/libnet/net_util_md.c??? Tue Jul 10 > 23:32:21 2018 -0700 > > @@ -117,6 +117,34 @@ > > return defaultIndex; > > } > > +/* > > + * Opens a socket > > + * On systems where supported, uses SOCK_CLOEXEC where possible > > + */ > > +int NET_SocketOpen(int domain, int type, int protocol) { > > +#if defined(SOCK_CLOEXEC) > > + int typeToUse = type | SOCK_CLOEXEC; > > +#else > > + int typeToUse = type; > > +#endif > > + > > + int socketFileDescriptor = socket(domain, typeToUse, protocol); > > +#if defined(SOCK_CLOEXEC) > > + if ((socketFileDescriptor == -1) && (errno = EINVAL)) { > > + // Attempt to open the socket without SOCK_CLOEXEC > > + // May have been compiled on an OS with SOCK_CLOEXEC supported > > + // But runtime system might not have SOCK_CLOEXEC support > > + socketFileDescriptor = socket(domain, type, protocol); > > + } > > +#else > > + // Best effort > > + // Return value is intentionally ignored since socket was > successfully opened anyways > > + fcntl(socketFileDescriptor, F_SETFD, FD_CLOEXEC); > > +#endif > > + > > + return socketFileDescriptor; > > +} > > + > > #define RESTARTABLE(_cmd, _result) do { \ > > do { \ > > _result = _cmd; \ > > @@ -295,7 +323,7 @@ > > SOCKETADDRESS sa; > > socklen_t sa_len = sizeof(SOCKETADDRESS); > > - fd = socket(AF_INET6, SOCK_STREAM, 0) ; > > + fd = NET_SocketOpen(AF_INET6, SOCK_STREAM, 0) ; > > if (fd < 0) { > > /* > > *? TODO: We really cant tell since it may be an unrelated error > > @@ -402,7 +430,7 @@ > > /* Do a simple dummy call, and try to figure out from that */ > > int one = 1; > > int rv, s; > > - s = socket(PF_INET, SOCK_STREAM, 0); > > + s = NET_SocketOpen(PF_INET, SOCK_STREAM, 0); > > if (s < 0) { > > return JNI_FALSE; > > } > > diff -r 95c0644a1c47 src/java.base/unix/native/libnet/net_util_md.h > > --- a/src/java.base/unix/native/libnet/net_util_md.h?????? Fri Jun 15 > 17:34:01 2018 -0700 > > +++ b/src/java.base/unix/native/libnet/net_util_md.h??? Tue Jul 10 > 23:32:21 2018 -0700 > > @@ -89,6 +89,7 @@ > > int NET_Writev(int s, const struct iovec * vector, int count); > > int NET_Connect(int s, struct sockaddr *addr, int addrlen); > > int NET_Accept(int s, struct sockaddr *addr, socklen_t *addrlen); > > +int NET_SocketOpen(int domain, int type, int protocol); > > int NET_SocketClose(int s); > > int NET_Dup2(int oldfd, int newfd); > > int NET_Poll(struct pollfd *ufds, unsigned int nfds, int timeout); > > *From:*Norman Maurer > *Sent:* Tuesday, July 10, 2018 9:55 AM > *To:* Alan Bateman > *Cc:* Martin Buchholz ; Andrew Luo > ; net-dev at openjdk.java.net > *Subject:* Re: [PATCH] SOCK_CLOEXEC for opening sockets > > +1 I think this makes a lot of sense > > > > On 10. Jul 2018, at 17:54, Alan Bateman > wrote: > > On 10/07/2018 17:40, Martin Buchholz wrote: > > I agree with this approach - it parallels the efforts made > with O_CLOEXEC in past years. > > > > According to > > https://www.freebsd.org/cgi/man.cgi?query=socket&sektion=2 > > SOCK_CLOEXEC is also available on freebsd. > > This is something that doesn't come up too often, I assume because > most developers using ProcessBuilder/Process rather than invoking > fork from native code. > > If we are going to tackle this issue then it will require changes > in several places, changing PlainSocketImpl.c is just one of several. > > -Alan > -------------- next part -------------- An HTML attachment was scrubbed... URL: From andrewluotechnologies at outlook.com Wed Jul 11 08:47:12 2018 From: andrewluotechnologies at outlook.com (Andrew Luo) Date: Wed, 11 Jul 2018 08:47:12 +0000 Subject: [PATCH] SOCK_CLOEXEC for opening sockets In-Reply-To: References: <0c24795d-350e-3ac8-4417-0480b41c5c9c@oracle.com> Message-ID: Sounds good. I've updated my patch: diff -r 95c0644a1c47 src/java.base/linux/native/libnio/fs/LinuxWatchService.c --- a/src/java.base/linux/native/libnio/fs/LinuxWatchService.c Fri Jun 15 17:34:01 2018 -0700 +++ b/src/java.base/linux/native/libnio/fs/LinuxWatchService.c Wed Jul 11 01:46:03 2018 -0700 @@ -119,7 +119,7 @@ (JNIEnv* env, jclass clazz, jintArray sv) { int sp[2]; - if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) == -1) { + if (NET_SocketPair(PF_UNIX, SOCK_STREAM, 0, sp) == -1) { throwUnixException(env, errno); } else { jint res[2]; diff -r 95c0644a1c47 src/java.base/unix/native/libnet/Inet4AddressImpl.c --- a/src/java.base/unix/native/libnet/Inet4AddressImpl.c Fri Jun 15 17:34:01 2018 -0700 +++ b/src/java.base/unix/native/libnet/Inet4AddressImpl.c Wed Jul 11 01:46:03 2018 -0700 @@ -264,7 +264,7 @@ int connect_rv = -1; // open a TCP socket - fd = socket(AF_INET, SOCK_STREAM, 0); + fd = NET_Socket(AF_INET, SOCK_STREAM, 0); if (fd == -1) { // note: if you run out of fds, you may not be able to load // the exception class, and get a NoClassDefFoundError instead. @@ -503,7 +503,7 @@ // Let's try to create a RAW socket to send ICMP packets. // This usually requires "root" privileges, so it's likely to fail. - fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); + fd = NET_Socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); if (fd == -1) { return tcp_ping4(env, &sa, netif, timeout, ttl); } else { diff -r 95c0644a1c47 src/java.base/unix/native/libnet/Inet6AddressImpl.c --- a/src/java.base/unix/native/libnet/Inet6AddressImpl.c Fri Jun 15 17:34:01 2018 -0700 +++ b/src/java.base/unix/native/libnet/Inet6AddressImpl.c Wed Jul 11 01:46:03 2018 -0700 @@ -461,7 +461,7 @@ int connect_rv = -1; // open a TCP socket - fd = socket(AF_INET6, SOCK_STREAM, 0); + fd = NET_Socket(AF_INET6, SOCK_STREAM, 0); if (fd == -1) { // note: if you run out of fds, you may not be able to load // the exception class, and get a NoClassDefFoundError instead. @@ -711,7 +711,7 @@ // Let's try to create a RAW socket to send ICMP packets. // This usually requires "root" privileges, so it's likely to fail. - fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); + fd = NET_Socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); if (fd == -1) { return tcp_ping6(env, &sa, netif, timeout, ttl); } else { diff -r 95c0644a1c47 src/java.base/unix/native/libnet/NetworkInterface.c --- a/src/java.base/unix/native/libnet/NetworkInterface.c Fri Jun 15 17:34:01 2018 -0700 +++ b/src/java.base/unix/native/libnet/NetworkInterface.c Wed Jul 11 01:46:03 2018 -0700 @@ -1055,7 +1055,7 @@ static int openSocket(JNIEnv *env, int proto) { int sock; - if ((sock = socket(proto, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(proto, SOCK_DGRAM, 0)) < 0) { // If EPROTONOSUPPORT is returned it means we don't have // support for this proto so don't throw an exception. if (errno != EPROTONOSUPPORT) { @@ -1078,9 +1078,9 @@ static int openSocketWithFallback(JNIEnv *env, const char *ifname) { int sock; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) { if (errno == EPROTONOSUPPORT) { - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; @@ -1315,9 +1315,9 @@ static int openSocketWithFallback(JNIEnv *env, const char *ifname) { int sock; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) { if (errno == EPROTONOSUPPORT) { - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; @@ -1590,9 +1590,9 @@ int sock, alreadyV6 = 0; struct lifreq if2; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) { if (errno == EPROTONOSUPPORT) { - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; @@ -1616,7 +1616,7 @@ strncpy(if2.lifr_name, ifname, sizeof(if2.lifr_name) - 1); if (ioctl(sock, SIOCGLIFNETMASK, (char *)&if2) < 0) { close(sock); - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; @@ -1941,9 +1941,9 @@ static int openSocketWithFallback(JNIEnv *env, const char *ifname) { int sock; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) { if (errno == EPROTONOSUPPORT) { - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; diff -r 95c0644a1c47 src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c --- a/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c Fri Jun 15 17:34:01 2018 -0700 +++ b/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c Wed Jul 11 01:46:03 2018 -0700 @@ -904,7 +904,7 @@ return; } - if ((fd = socket(domain, SOCK_DGRAM, 0)) == -1) { + if ((fd = NET_Socket(domain, SOCK_DGRAM, 0)) == -1) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "Error creating socket"); return; diff -r 95c0644a1c47 src/java.base/unix/native/libnet/PlainSocketImpl.c --- a/src/java.base/unix/native/libnet/PlainSocketImpl.c Fri Jun 15 17:34:01 2018 -0700 +++ b/src/java.base/unix/native/libnet/PlainSocketImpl.c Wed Jul 11 01:46:03 2018 -0700 @@ -178,7 +178,7 @@ return; } - if ((fd = socket(domain, type, 0)) == -1) { + if ((fd = NET_Socket(domain, type, 0)) == -1) { /* note: if you run out of fds, you may not be able to load * the exception class, and get a NoClassDefFoundError * instead. diff -r 95c0644a1c47 src/java.base/unix/native/libnet/SdpSupport.c --- a/src/java.base/unix/native/libnet/SdpSupport.c Fri Jun 15 17:34:01 2018 -0700 +++ b/src/java.base/unix/native/libnet/SdpSupport.c Wed Jul 11 01:46:03 2018 -0700 @@ -57,7 +57,7 @@ #if defined(__solaris__) int domain = ipv6_available() ? AF_INET6 : AF_INET; - s = socket(domain, SOCK_STREAM, PROTO_SDP); + s = NET_Socket(domain, SOCK_STREAM, PROTO_SDP); #elif defined(__linux__) /** * IPv6 not supported by SDP on Linux @@ -66,7 +66,7 @@ JNU_ThrowIOException(env, "IPv6 not supported"); return -1; } - s = socket(AF_INET_SDP, SOCK_STREAM, 0); + s = NET_Socket(AF_INET_SDP, SOCK_STREAM, 0); #else /* not supported on other platforms at this time */ s = -1; diff -r 95c0644a1c47 src/java.base/unix/native/libnet/net_util_md.c --- a/src/java.base/unix/native/libnet/net_util_md.c Fri Jun 15 17:34:01 2018 -0700 +++ b/src/java.base/unix/native/libnet/net_util_md.c Wed Jul 11 01:46:03 2018 -0700 @@ -117,6 +117,60 @@ return defaultIndex; } +/* + * Opens a socket + * On systems where supported, uses SOCK_CLOEXEC where possible + */ +JNIEXPORT int JNICALL +NET_Socket(int domain, int type, int protocol) { +#if defined(SOCK_CLOEXEC) + int typeToUse = type | SOCK_CLOEXEC; +#else + int typeToUse = type; +#endif + + int socketFileDescriptor = socket(domain, typeToUse, protocol); +#if defined(SOCK_CLOEXEC) + if ((socketFileDescriptor == -1) && (errno = EINVAL)) { + // Attempt to open the socket without SOCK_CLOEXEC + // May have been compiled on an OS with SOCK_CLOEXEC supported + // But runtime system might not have SOCK_CLOEXEC support + socketFileDescriptor = socket(domain, type, protocol); + } +#else + // Best effort + // Return value is intentionally ignored since socket was successfully opened anyways + fcntl(socketFileDescriptor, F_SETFD, FD_CLOEXEC); +#endif + + return socketFileDescriptor; +} + +JNIEXPORT int JNICALL +NET_SocketPair(int domain, int type, int protocol, int socket_vector[2]) { +#if defined(SOCK_CLOEXEC) + int typeToUse = type | SOCK_CLOEXEC; +#else + int typeToUse = type; +#endif + + int socketFileDescriptor = socketpair(domain, typeToUse, protocol, socket_vector); +#if defined(SOCK_CLOEXEC) + if ((socketFileDescriptor == -1) && (errno = EINVAL)) { + // Attempt to open the socket without SOCK_CLOEXEC + // May have been compiled on an OS with SOCK_CLOEXEC supported + // But runtime system might not have SOCK_CLOEXEC support + socketFileDescriptor = socketpair(domain, type, protocol, socket_vector); + } +#else + // Best effort + // Return value is intentionally ignored since socket was successfully opened anyways + fcntl(socketFileDescriptor, F_SETFD, FD_CLOEXEC); +#endif + + return socketFileDescriptor; +} + #define RESTARTABLE(_cmd, _result) do { \ do { \ _result = _cmd; \ @@ -295,7 +349,7 @@ SOCKETADDRESS sa; socklen_t sa_len = sizeof(SOCKETADDRESS); - fd = socket(AF_INET6, SOCK_STREAM, 0) ; + fd = NET_Socket(AF_INET6, SOCK_STREAM, 0) ; if (fd < 0) { /* * TODO: We really cant tell since it may be an unrelated error @@ -402,7 +456,7 @@ /* Do a simple dummy call, and try to figure out from that */ int one = 1; int rv, s; - s = socket(PF_INET, SOCK_STREAM, 0); + s = NET_Socket(PF_INET, SOCK_STREAM, 0); if (s < 0) { return JNI_FALSE; } diff -r 95c0644a1c47 src/java.base/unix/native/libnet/net_util_md.h --- a/src/java.base/unix/native/libnet/net_util_md.h Fri Jun 15 17:34:01 2018 -0700 +++ b/src/java.base/unix/native/libnet/net_util_md.h Wed Jul 11 01:46:03 2018 -0700 @@ -89,6 +89,8 @@ int NET_Writev(int s, const struct iovec * vector, int count); int NET_Connect(int s, struct sockaddr *addr, int addrlen); int NET_Accept(int s, struct sockaddr *addr, socklen_t *addrlen); +JNIEXPORT int JNICALL NET_Socket(int domain, int type, int protocol); +JNIEXPORT int JNICALL NET_SocketPair(int domain, int type, int protocol, int socket_vector[2]); int NET_SocketClose(int s); int NET_Dup2(int oldfd, int newfd); int NET_Poll(struct pollfd *ufds, unsigned int nfds, int timeout); diff -r 95c0644a1c47 src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c --- a/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c Fri Jun 15 17:34:01 2018 -0700 +++ b/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c Wed Jul 11 01:46:03 2018 -0700 @@ -67,7 +67,7 @@ Java_sun_nio_ch_FileDispatcherImpl_init(JNIEnv *env, jclass cl) { int sp[2]; - if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) { + if (NET_SocketPair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) { JNU_ThrowIOExceptionWithLastError(env, "socketpair failed"); return; } diff -r 95c0644a1c47 src/java.base/unix/native/libnio/ch/Net.c --- a/src/java.base/unix/native/libnio/ch/Net.c Fri Jun 15 17:34:01 2018 -0700 +++ b/src/java.base/unix/native/libnio/ch/Net.c Wed Jul 11 01:46:03 2018 -0700 @@ -198,7 +198,7 @@ int type = (stream ? SOCK_STREAM : SOCK_DGRAM); int domain = (ipv6_available() && preferIPv6) ? AF_INET6 : AF_INET; - fd = socket(domain, type, 0); + fd = NET_Socket(domain, type, 0); if (fd < 0) { return handleSocketError(env, errno); } From: Alan Bateman Sent: Wednesday, July 11, 2018 12:12 AM To: Andrew Luo ; Norman Maurer Cc: Martin Buchholz ; net-dev at openjdk.java.net Subject: Re: [PATCH] SOCK_CLOEXEC for opening sockets This seems to cover the sockets created in libnet but there is also a usage in libnio that will need update. It might be cleaner to name it NET_Socket to be consistent with the other wrappers (NET_Bind, NET_SetSocketOpt, etc.). There are a lot of other file descriptors that you may run into. We use socketpair in a few places, we have file descriptors for epoll and more. It makes me wonder if it would be better to use FD_CLOEXEC consistently. In the Windows port then you'll see that we change the inheritance flag on all newly created SOCKETs, that is because is because we don't have the same opportunity to close inherited handles in the child process that we do on Unix platforms. -Alan On 11/07/2018 07:35, Andrew Luo wrote: I agree, I wasn't aware of the other uses of ::socket in the libnet codebase. Thus, I've added a new common function, NET_SocketOpen that can be used by all the source files in libnet and revised my patch: diff -r 95c0644a1c47 src/java.base/unix/native/libnet/Inet4AddressImpl.c --- a/src/java.base/unix/native/libnet/Inet4AddressImpl.c Fri Jun 15 17:34:01 2018 -0700 +++ b/src/java.base/unix/native/libnet/Inet4AddressImpl.c Tue Jul 10 23:32:21 2018 -0700 @@ -264,7 +264,7 @@ int connect_rv = -1; // open a TCP socket - fd = socket(AF_INET, SOCK_STREAM, 0); + fd = NET_SocketOpen(AF_INET, SOCK_STREAM, 0); if (fd == -1) { // note: if you run out of fds, you may not be able to load // the exception class, and get a NoClassDefFoundError instead. @@ -503,7 +503,7 @@ // Let's try to create a RAW socket to send ICMP packets. // This usually requires "root" privileges, so it's likely to fail. - fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); + fd = NET_SocketOpen(AF_INET, SOCK_RAW, IPPROTO_ICMP); if (fd == -1) { return tcp_ping4(env, &sa, netif, timeout, ttl); } else { diff -r 95c0644a1c47 src/java.base/unix/native/libnet/Inet6AddressImpl.c --- a/src/java.base/unix/native/libnet/Inet6AddressImpl.c Fri Jun 15 17:34:01 2018 -0700 +++ b/src/java.base/unix/native/libnet/Inet6AddressImpl.c Tue Jul 10 23:32:21 2018 -0700 @@ -461,7 +461,7 @@ int connect_rv = -1; // open a TCP socket - fd = socket(AF_INET6, SOCK_STREAM, 0); + fd = NET_SocketOpen(AF_INET6, SOCK_STREAM, 0); if (fd == -1) { // note: if you run out of fds, you may not be able to load // the exception class, and get a NoClassDefFoundError instead. @@ -711,7 +711,7 @@ // Let's try to create a RAW socket to send ICMP packets. // This usually requires "root" privileges, so it's likely to fail. - fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); + fd = NET_SocketOpen(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); if (fd == -1) { return tcp_ping6(env, &sa, netif, timeout, ttl); } else { diff -r 95c0644a1c47 src/java.base/unix/native/libnet/NetworkInterface.c --- a/src/java.base/unix/native/libnet/NetworkInterface.c Fri Jun 15 17:34:01 2018 -0700 +++ b/src/java.base/unix/native/libnet/NetworkInterface.c Tue Jul 10 23:32:21 2018 -0700 @@ -1055,7 +1055,7 @@ static int openSocket(JNIEnv *env, int proto) { int sock; - if ((sock = socket(proto, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_SocketOpen(proto, SOCK_DGRAM, 0)) < 0) { // If EPROTONOSUPPORT is returned it means we don't have // support for this proto so don't throw an exception. if (errno != EPROTONOSUPPORT) { @@ -1078,9 +1078,9 @@ static int openSocketWithFallback(JNIEnv *env, const char *ifname) { int sock; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_SocketOpen(AF_INET, SOCK_DGRAM, 0)) < 0) { if (errno == EPROTONOSUPPORT) { - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_SocketOpen(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; @@ -1315,9 +1315,9 @@ static int openSocketWithFallback(JNIEnv *env, const char *ifname) { int sock; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_SocketOpen(AF_INET, SOCK_DGRAM, 0)) < 0) { if (errno == EPROTONOSUPPORT) { - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_SocketOpen(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; @@ -1590,9 +1590,9 @@ int sock, alreadyV6 = 0; struct lifreq if2; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_SocketOpen(AF_INET, SOCK_DGRAM, 0)) < 0) { if (errno == EPROTONOSUPPORT) { - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_SocketOpen(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; @@ -1616,7 +1616,7 @@ strncpy(if2.lifr_name, ifname, sizeof(if2.lifr_name) - 1); if (ioctl(sock, SIOCGLIFNETMASK, (char *)&if2) < 0) { close(sock); - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_SocketOpen(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; @@ -1941,9 +1941,9 @@ static int openSocketWithFallback(JNIEnv *env, const char *ifname) { int sock; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_SocketOpen(AF_INET, SOCK_DGRAM, 0)) < 0) { if (errno == EPROTONOSUPPORT) { - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_SocketOpen(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; diff -r 95c0644a1c47 src/java.base/unix/native/libnet/PlainSocketImpl.c --- a/src/java.base/unix/native/libnet/PlainSocketImpl.c Fri Jun 15 17:34:01 2018 -0700 +++ b/src/java.base/unix/native/libnet/PlainSocketImpl.c Tue Jul 10 23:32:21 2018 -0700 @@ -178,7 +178,7 @@ return; } - if ((fd = socket(domain, type, 0)) == -1) { + if ((fd = NET_SocketOpen(domain, type, 0)) == -1) { /* note: if you run out of fds, you may not be able to load * the exception class, and get a NoClassDefFoundError * instead. diff -r 95c0644a1c47 src/java.base/unix/native/libnet/SdpSupport.c --- a/src/java.base/unix/native/libnet/SdpSupport.c Fri Jun 15 17:34:01 2018 -0700 +++ b/src/java.base/unix/native/libnet/SdpSupport.c Tue Jul 10 23:32:21 2018 -0700 @@ -57,7 +57,7 @@ #if defined(__solaris__) int domain = ipv6_available() ? AF_INET6 : AF_INET; - s = socket(domain, SOCK_STREAM, PROTO_SDP); + s = NET_SocketOpen(domain, SOCK_STREAM, PROTO_SDP); #elif defined(__linux__) /** * IPv6 not supported by SDP on Linux @@ -66,7 +66,7 @@ JNU_ThrowIOException(env, "IPv6 not supported"); return -1; } - s = socket(AF_INET_SDP, SOCK_STREAM, 0); + s = NET_SocketOpen(AF_INET_SDP, SOCK_STREAM, 0); #else /* not supported on other platforms at this time */ s = -1; diff -r 95c0644a1c47 src/java.base/unix/native/libnet/net_util_md.c --- a/src/java.base/unix/native/libnet/net_util_md.c Fri Jun 15 17:34:01 2018 -0700 +++ b/src/java.base/unix/native/libnet/net_util_md.c Tue Jul 10 23:32:21 2018 -0700 @@ -117,6 +117,34 @@ return defaultIndex; } +/* + * Opens a socket + * On systems where supported, uses SOCK_CLOEXEC where possible + */ +int NET_SocketOpen(int domain, int type, int protocol) { +#if defined(SOCK_CLOEXEC) + int typeToUse = type | SOCK_CLOEXEC; +#else + int typeToUse = type; +#endif + + int socketFileDescriptor = socket(domain, typeToUse, protocol); +#if defined(SOCK_CLOEXEC) + if ((socketFileDescriptor == -1) && (errno = EINVAL)) { + // Attempt to open the socket without SOCK_CLOEXEC + // May have been compiled on an OS with SOCK_CLOEXEC supported + // But runtime system might not have SOCK_CLOEXEC support + socketFileDescriptor = socket(domain, type, protocol); + } +#else + // Best effort + // Return value is intentionally ignored since socket was successfully opened anyways + fcntl(socketFileDescriptor, F_SETFD, FD_CLOEXEC); +#endif + + return socketFileDescriptor; +} + #define RESTARTABLE(_cmd, _result) do { \ do { \ _result = _cmd; \ @@ -295,7 +323,7 @@ SOCKETADDRESS sa; socklen_t sa_len = sizeof(SOCKETADDRESS); - fd = socket(AF_INET6, SOCK_STREAM, 0) ; + fd = NET_SocketOpen(AF_INET6, SOCK_STREAM, 0) ; if (fd < 0) { /* * TODO: We really cant tell since it may be an unrelated error @@ -402,7 +430,7 @@ /* Do a simple dummy call, and try to figure out from that */ int one = 1; int rv, s; - s = socket(PF_INET, SOCK_STREAM, 0); + s = NET_SocketOpen(PF_INET, SOCK_STREAM, 0); if (s < 0) { return JNI_FALSE; } diff -r 95c0644a1c47 src/java.base/unix/native/libnet/net_util_md.h --- a/src/java.base/unix/native/libnet/net_util_md.h Fri Jun 15 17:34:01 2018 -0700 +++ b/src/java.base/unix/native/libnet/net_util_md.h Tue Jul 10 23:32:21 2018 -0700 @@ -89,6 +89,7 @@ int NET_Writev(int s, const struct iovec * vector, int count); int NET_Connect(int s, struct sockaddr *addr, int addrlen); int NET_Accept(int s, struct sockaddr *addr, socklen_t *addrlen); +int NET_SocketOpen(int domain, int type, int protocol); int NET_SocketClose(int s); int NET_Dup2(int oldfd, int newfd); int NET_Poll(struct pollfd *ufds, unsigned int nfds, int timeout); From: Norman Maurer Sent: Tuesday, July 10, 2018 9:55 AM To: Alan Bateman Cc: Martin Buchholz ; Andrew Luo ; net-dev at openjdk.java.net Subject: Re: [PATCH] SOCK_CLOEXEC for opening sockets +1 I think this makes a lot of sense On 10. Jul 2018, at 17:54, Alan Bateman > wrote: On 10/07/2018 17:40, Martin Buchholz wrote: I agree with this approach - it parallels the efforts made with O_CLOEXEC in past years. According to https://www.freebsd.org/cgi/man.cgi?query=socket&sektion=2 SOCK_CLOEXEC is also available on freebsd. This is something that doesn't come up too often, I assume because most developers using ProcessBuilder/Process rather than invoking fork from native code. If we are going to tackle this issue then it will require changes in several places, changing PlainSocketImpl.c is just one of several. -Alan -------------- next part -------------- An HTML attachment was scrubbed... URL: From andrewluotechnologies at outlook.com Thu Jul 12 04:55:41 2018 From: andrewluotechnologies at outlook.com (Andrew Luo) Date: Thu, 12 Jul 2018 04:55:41 +0000 Subject: [PATCH] SOCK_CLOEXEC for opening sockets References: <0c24795d-350e-3ac8-4417-0480b41c5c9c@oracle.com> Message-ID: Ok, fixed a few more places (and a bug where fcntl was being run on a -1 fd). Patch is below, let me know if there's any other suggestions/etc. By the way, is anyone willing to sponsor this change? I'm not a committer/author, this is my first OpenJDK contribution. Thanks, -Andrew diff --git a/src/java.base/linux/native/libnio/fs/LinuxWatchService.c b/src/java.base/linux/native/libnio/fs/LinuxWatchService.c --- a/src/java.base/linux/native/libnio/fs/LinuxWatchService.c +++ b/src/java.base/linux/native/libnio/fs/LinuxWatchService.c @@ -119,7 +119,7 @@ (JNIEnv* env, jclass clazz, jintArray sv) { int sp[2]; - if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) == -1) { + if (NET_SocketPair(PF_UNIX, SOCK_STREAM, 0, sp) == -1) { throwUnixException(env, errno); } else { jint res[2]; diff --git a/src/java.base/unix/native/libnet/Inet4AddressImpl.c b/src/java.base/unix/native/libnet/Inet4AddressImpl.c --- a/src/java.base/unix/native/libnet/Inet4AddressImpl.c +++ b/src/java.base/unix/native/libnet/Inet4AddressImpl.c @@ -264,7 +264,7 @@ int connect_rv = -1; // open a TCP socket - fd = socket(AF_INET, SOCK_STREAM, 0); + fd = NET_Socket(AF_INET, SOCK_STREAM, 0); if (fd == -1) { // note: if you run out of fds, you may not be able to load // the exception class, and get a NoClassDefFoundError instead. @@ -503,7 +503,7 @@ // Let's try to create a RAW socket to send ICMP packets. // This usually requires "root" privileges, so it's likely to fail. - fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); + fd = NET_Socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); if (fd == -1) { return tcp_ping4(env, &sa, netif, timeout, ttl); } else { diff --git a/src/java.base/unix/native/libnet/Inet6AddressImpl.c b/src/java.base/unix/native/libnet/Inet6AddressImpl.c --- a/src/java.base/unix/native/libnet/Inet6AddressImpl.c +++ b/src/java.base/unix/native/libnet/Inet6AddressImpl.c @@ -461,7 +461,7 @@ int connect_rv = -1; // open a TCP socket - fd = socket(AF_INET6, SOCK_STREAM, 0); + fd = NET_Socket(AF_INET6, SOCK_STREAM, 0); if (fd == -1) { // note: if you run out of fds, you may not be able to load // the exception class, and get a NoClassDefFoundError instead. @@ -711,7 +711,7 @@ // Let's try to create a RAW socket to send ICMP packets. // This usually requires "root" privileges, so it's likely to fail. - fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); + fd = NET_Socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); if (fd == -1) { return tcp_ping6(env, &sa, netif, timeout, ttl); } else { diff --git a/src/java.base/unix/native/libnet/NetworkInterface.c b/src/java.base/unix/native/libnet/NetworkInterface.c --- a/src/java.base/unix/native/libnet/NetworkInterface.c +++ b/src/java.base/unix/native/libnet/NetworkInterface.c @@ -1055,7 +1055,7 @@ static int openSocket(JNIEnv *env, int proto) { int sock; - if ((sock = socket(proto, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(proto, SOCK_DGRAM, 0)) < 0) { // If EPROTONOSUPPORT is returned it means we don't have // support for this proto so don't throw an exception. if (errno != EPROTONOSUPPORT) { @@ -1078,9 +1078,9 @@ static int openSocketWithFallback(JNIEnv *env, const char *ifname) { int sock; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) { if (errno == EPROTONOSUPPORT) { - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; @@ -1315,9 +1315,9 @@ static int openSocketWithFallback(JNIEnv *env, const char *ifname) { int sock; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) { if (errno == EPROTONOSUPPORT) { - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; @@ -1590,9 +1590,9 @@ int sock, alreadyV6 = 0; struct lifreq if2; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) { if (errno == EPROTONOSUPPORT) { - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; @@ -1616,7 +1616,7 @@ strncpy(if2.lifr_name, ifname, sizeof(if2.lifr_name) - 1); if (ioctl(sock, SIOCGLIFNETMASK, (char *)&if2) < 0) { close(sock); - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; @@ -1941,9 +1941,9 @@ static int openSocketWithFallback(JNIEnv *env, const char *ifname) { int sock; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) { if (errno == EPROTONOSUPPORT) { - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; diff --git a/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c b/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c --- a/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c +++ b/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c @@ -904,7 +904,7 @@ return; } - if ((fd = socket(domain, SOCK_DGRAM, 0)) == -1) { + if ((fd = NET_Socket(domain, SOCK_DGRAM, 0)) == -1) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "Error creating socket"); return; diff --git a/src/java.base/unix/native/libnet/PlainSocketImpl.c b/src/java.base/unix/native/libnet/PlainSocketImpl.c --- a/src/java.base/unix/native/libnet/PlainSocketImpl.c +++ b/src/java.base/unix/native/libnet/PlainSocketImpl.c @@ -77,7 +77,7 @@ int sv[2]; #ifdef AF_UNIX - if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == -1) { + if (NET_SocketPair(AF_UNIX, SOCK_STREAM, 0, sv) == -1) { return -1; } #else @@ -178,7 +178,7 @@ return; } - if ((fd = socket(domain, type, 0)) == -1) { + if ((fd = NET_Socket(domain, type, 0)) == -1) { /* note: if you run out of fds, you may not be able to load * the exception class, and get a NoClassDefFoundError * instead. diff --git a/src/java.base/unix/native/libnet/SdpSupport.c b/src/java.base/unix/native/libnet/SdpSupport.c --- a/src/java.base/unix/native/libnet/SdpSupport.c +++ b/src/java.base/unix/native/libnet/SdpSupport.c @@ -57,7 +57,7 @@ #if defined(__solaris__) int domain = ipv6_available() ? AF_INET6 : AF_INET; - s = socket(domain, SOCK_STREAM, PROTO_SDP); + s = NET_Socket(domain, SOCK_STREAM, PROTO_SDP); #elif defined(__linux__) /** * IPv6 not supported by SDP on Linux @@ -66,7 +66,7 @@ JNU_ThrowIOException(env, "IPv6 not supported"); return -1; } - s = socket(AF_INET_SDP, SOCK_STREAM, 0); + s = NET_Socket(AF_INET_SDP, SOCK_STREAM, 0); #else /* not supported on other platforms at this time */ s = -1; diff --git a/src/java.base/unix/native/libnet/net_util_md.c b/src/java.base/unix/native/libnet/net_util_md.c --- a/src/java.base/unix/native/libnet/net_util_md.c +++ b/src/java.base/unix/native/libnet/net_util_md.c @@ -117,6 +117,64 @@ return defaultIndex; } +/* + * Opens a socket + * On systems where supported, uses SOCK_CLOEXEC where possible + */ +JNIEXPORT int JNICALL +NET_Socket(int domain, int type, int protocol) { +#if defined(SOCK_CLOEXEC) + int typeToUse = type | SOCK_CLOEXEC; +#else + int typeToUse = type; +#endif + + int socketFileDescriptor = socket(domain, typeToUse, protocol); +#if defined(SOCK_CLOEXEC) + if ((socketFileDescriptor == -1) && (errno = EINVAL)) { + // Attempt to open the socket without SOCK_CLOEXEC + // May have been compiled on an OS with SOCK_CLOEXEC supported + // But runtime system might not have SOCK_CLOEXEC support + socketFileDescriptor = socket(domain, type, protocol); + } +#else + if (socketFileDescriptor != -1) { + // Best effort + // Return value is intentionally ignored since socket was successfully opened anyways + fcntl(socketFileDescriptor, F_SETFD, FD_CLOEXEC); + } +#endif + + return socketFileDescriptor; +} + +JNIEXPORT int JNICALL +NET_SocketPair(int domain, int type, int protocol, int socket_vector[2]) { +#if defined(SOCK_CLOEXEC) + int typeToUse = type | SOCK_CLOEXEC; +#else + int typeToUse = type; +#endif + + int socketFileDescriptor = socketpair(domain, typeToUse, protocol, socket_vector); +#if defined(SOCK_CLOEXEC) + if ((socketFileDescriptor == -1) && (errno = EINVAL)) { + // Attempt to open the socket without SOCK_CLOEXEC + // May have been compiled on an OS with SOCK_CLOEXEC supported + // But runtime system might not have SOCK_CLOEXEC support + socketFileDescriptor = socketpair(domain, type, protocol, socket_vector); + } +#else + if (socketFileDescriptor != -1) { + // Best effort + // Return value is intentionally ignored since socket was successfully opened anyways + fcntl(socketFileDescriptor, F_SETFD, FD_CLOEXEC); + } +#endif + + return socketFileDescriptor; +} + #define RESTARTABLE(_cmd, _result) do { \ do { \ _result = _cmd; \ @@ -295,7 +353,7 @@ SOCKETADDRESS sa; socklen_t sa_len = sizeof(SOCKETADDRESS); - fd = socket(AF_INET6, SOCK_STREAM, 0) ; + fd = NET_Socket(AF_INET6, SOCK_STREAM, 0) ; if (fd < 0) { /* * TODO: We really cant tell since it may be an unrelated error @@ -402,7 +460,7 @@ /* Do a simple dummy call, and try to figure out from that */ int one = 1; int rv, s; - s = socket(PF_INET, SOCK_STREAM, 0); + s = NET_Socket(PF_INET, SOCK_STREAM, 0); if (s < 0) { return JNI_FALSE; } diff --git a/src/java.base/unix/native/libnet/net_util_md.h b/src/java.base/unix/native/libnet/net_util_md.h --- a/src/java.base/unix/native/libnet/net_util_md.h +++ b/src/java.base/unix/native/libnet/net_util_md.h @@ -89,6 +89,8 @@ int NET_Writev(int s, const struct iovec * vector, int count); int NET_Connect(int s, struct sockaddr *addr, int addrlen); int NET_Accept(int s, struct sockaddr *addr, socklen_t *addrlen); +JNIEXPORT int JNICALL NET_Socket(int domain, int type, int protocol); +JNIEXPORT int JNICALL NET_SocketPair(int domain, int type, int protocol, int socket_vector[2]); int NET_SocketClose(int s); int NET_Dup2(int oldfd, int newfd); int NET_Poll(struct pollfd *ufds, unsigned int nfds, int timeout); diff --git a/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c b/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c --- a/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c +++ b/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c @@ -67,7 +67,7 @@ Java_sun_nio_ch_FileDispatcherImpl_init(JNIEnv *env, jclass cl) { int sp[2]; - if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) { + if (NET_SocketPair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) { JNU_ThrowIOExceptionWithLastError(env, "socketpair failed"); return; } diff --git a/src/java.base/unix/native/libnio/ch/Net.c b/src/java.base/unix/native/libnio/ch/Net.c --- a/src/java.base/unix/native/libnio/ch/Net.c +++ b/src/java.base/unix/native/libnio/ch/Net.c @@ -198,7 +198,7 @@ int type = (stream ? SOCK_STREAM : SOCK_DGRAM); int domain = (ipv6_available() && preferIPv6) ? AF_INET6 : AF_INET; - fd = socket(domain, type, 0); + fd = NET_Socket(domain, type, 0); if (fd < 0) { return handleSocketError(env, errno); } diff --git a/src/jdk.sctp/unix/native/libsctp/SctpNet.c b/src/jdk.sctp/unix/native/libsctp/SctpNet.c --- a/src/jdk.sctp/unix/native/libsctp/SctpNet.c +++ b/src/jdk.sctp/unix/native/libsctp/SctpNet.c @@ -151,7 +151,7 @@ Java_sun_nio_ch_sctp_SctpNet_init (JNIEnv *env, jclass cl) { int sp[2]; - if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) { + if (NET_SocketPair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) { JNU_ThrowIOExceptionWithLastError(env, "socketpair failed"); return; } @@ -180,7 +180,7 @@ return 0; } - fd = socket(domain, (oneToOne ? SOCK_STREAM : SOCK_SEQPACKET), IPPROTO_SCTP); + fd = NET_Socket(domain, (oneToOne ? SOCK_STREAM : SOCK_SEQPACKET), IPPROTO_SCTP); if (fd < 0) { return handleSocketError(env, errno); From: Andrew Luo Sent: Wednesday, July 11, 2018 1:47 AM To: 'Alan Bateman' ; Norman Maurer Cc: Martin Buchholz ; net-dev at openjdk.java.net Subject: RE: [PATCH] SOCK_CLOEXEC for opening sockets Sounds good. I've updated my patch: diff -r 95c0644a1c47 src/java.base/linux/native/libnio/fs/LinuxWatchService.c --- a/src/java.base/linux/native/libnio/fs/LinuxWatchService.c Fri Jun 15 17:34:01 2018 -0700 +++ b/src/java.base/linux/native/libnio/fs/LinuxWatchService.c Wed Jul 11 01:46:03 2018 -0700 @@ -119,7 +119,7 @@ (JNIEnv* env, jclass clazz, jintArray sv) { int sp[2]; - if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) == -1) { + if (NET_SocketPair(PF_UNIX, SOCK_STREAM, 0, sp) == -1) { throwUnixException(env, errno); } else { jint res[2]; diff -r 95c0644a1c47 src/java.base/unix/native/libnet/Inet4AddressImpl.c --- a/src/java.base/unix/native/libnet/Inet4AddressImpl.c Fri Jun 15 17:34:01 2018 -0700 +++ b/src/java.base/unix/native/libnet/Inet4AddressImpl.c Wed Jul 11 01:46:03 2018 -0700 @@ -264,7 +264,7 @@ int connect_rv = -1; // open a TCP socket - fd = socket(AF_INET, SOCK_STREAM, 0); + fd = NET_Socket(AF_INET, SOCK_STREAM, 0); if (fd == -1) { // note: if you run out of fds, you may not be able to load // the exception class, and get a NoClassDefFoundError instead. @@ -503,7 +503,7 @@ // Let's try to create a RAW socket to send ICMP packets. // This usually requires "root" privileges, so it's likely to fail. - fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); + fd = NET_Socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); if (fd == -1) { return tcp_ping4(env, &sa, netif, timeout, ttl); } else { diff -r 95c0644a1c47 src/java.base/unix/native/libnet/Inet6AddressImpl.c --- a/src/java.base/unix/native/libnet/Inet6AddressImpl.c Fri Jun 15 17:34:01 2018 -0700 +++ b/src/java.base/unix/native/libnet/Inet6AddressImpl.c Wed Jul 11 01:46:03 2018 -0700 @@ -461,7 +461,7 @@ int connect_rv = -1; // open a TCP socket - fd = socket(AF_INET6, SOCK_STREAM, 0); + fd = NET_Socket(AF_INET6, SOCK_STREAM, 0); if (fd == -1) { // note: if you run out of fds, you may not be able to load // the exception class, and get a NoClassDefFoundError instead. @@ -711,7 +711,7 @@ // Let's try to create a RAW socket to send ICMP packets. // This usually requires "root" privileges, so it's likely to fail. - fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); + fd = NET_Socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); if (fd == -1) { return tcp_ping6(env, &sa, netif, timeout, ttl); } else { diff -r 95c0644a1c47 src/java.base/unix/native/libnet/NetworkInterface.c --- a/src/java.base/unix/native/libnet/NetworkInterface.c Fri Jun 15 17:34:01 2018 -0700 +++ b/src/java.base/unix/native/libnet/NetworkInterface.c Wed Jul 11 01:46:03 2018 -0700 @@ -1055,7 +1055,7 @@ static int openSocket(JNIEnv *env, int proto) { int sock; - if ((sock = socket(proto, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(proto, SOCK_DGRAM, 0)) < 0) { // If EPROTONOSUPPORT is returned it means we don't have // support for this proto so don't throw an exception. if (errno != EPROTONOSUPPORT) { @@ -1078,9 +1078,9 @@ static int openSocketWithFallback(JNIEnv *env, const char *ifname) { int sock; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) { if (errno == EPROTONOSUPPORT) { - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; @@ -1315,9 +1315,9 @@ static int openSocketWithFallback(JNIEnv *env, const char *ifname) { int sock; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) { if (errno == EPROTONOSUPPORT) { - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; @@ -1590,9 +1590,9 @@ int sock, alreadyV6 = 0; struct lifreq if2; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) { if (errno == EPROTONOSUPPORT) { - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; @@ -1616,7 +1616,7 @@ strncpy(if2.lifr_name, ifname, sizeof(if2.lifr_name) - 1); if (ioctl(sock, SIOCGLIFNETMASK, (char *)&if2) < 0) { close(sock); - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; @@ -1941,9 +1941,9 @@ static int openSocketWithFallback(JNIEnv *env, const char *ifname) { int sock; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) { if (errno == EPROTONOSUPPORT) { - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; diff -r 95c0644a1c47 src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c --- a/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c Fri Jun 15 17:34:01 2018 -0700 +++ b/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c Wed Jul 11 01:46:03 2018 -0700 @@ -904,7 +904,7 @@ return; } - if ((fd = socket(domain, SOCK_DGRAM, 0)) == -1) { + if ((fd = NET_Socket(domain, SOCK_DGRAM, 0)) == -1) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "Error creating socket"); return; diff -r 95c0644a1c47 src/java.base/unix/native/libnet/PlainSocketImpl.c --- a/src/java.base/unix/native/libnet/PlainSocketImpl.c Fri Jun 15 17:34:01 2018 -0700 +++ b/src/java.base/unix/native/libnet/PlainSocketImpl.c Wed Jul 11 01:46:03 2018 -0700 @@ -178,7 +178,7 @@ return; } - if ((fd = socket(domain, type, 0)) == -1) { + if ((fd = NET_Socket(domain, type, 0)) == -1) { /* note: if you run out of fds, you may not be able to load * the exception class, and get a NoClassDefFoundError * instead. diff -r 95c0644a1c47 src/java.base/unix/native/libnet/SdpSupport.c --- a/src/java.base/unix/native/libnet/SdpSupport.c Fri Jun 15 17:34:01 2018 -0700 +++ b/src/java.base/unix/native/libnet/SdpSupport.c Wed Jul 11 01:46:03 2018 -0700 @@ -57,7 +57,7 @@ #if defined(__solaris__) int domain = ipv6_available() ? AF_INET6 : AF_INET; - s = socket(domain, SOCK_STREAM, PROTO_SDP); + s = NET_Socket(domain, SOCK_STREAM, PROTO_SDP); #elif defined(__linux__) /** * IPv6 not supported by SDP on Linux @@ -66,7 +66,7 @@ JNU_ThrowIOException(env, "IPv6 not supported"); return -1; } - s = socket(AF_INET_SDP, SOCK_STREAM, 0); + s = NET_Socket(AF_INET_SDP, SOCK_STREAM, 0); #else /* not supported on other platforms at this time */ s = -1; diff -r 95c0644a1c47 src/java.base/unix/native/libnet/net_util_md.c --- a/src/java.base/unix/native/libnet/net_util_md.c Fri Jun 15 17:34:01 2018 -0700 +++ b/src/java.base/unix/native/libnet/net_util_md.c Wed Jul 11 01:46:03 2018 -0700 @@ -117,6 +117,60 @@ return defaultIndex; } +/* + * Opens a socket + * On systems where supported, uses SOCK_CLOEXEC where possible + */ +JNIEXPORT int JNICALL +NET_Socket(int domain, int type, int protocol) { +#if defined(SOCK_CLOEXEC) + int typeToUse = type | SOCK_CLOEXEC; +#else + int typeToUse = type; +#endif + + int socketFileDescriptor = socket(domain, typeToUse, protocol); +#if defined(SOCK_CLOEXEC) + if ((socketFileDescriptor == -1) && (errno = EINVAL)) { + // Attempt to open the socket without SOCK_CLOEXEC + // May have been compiled on an OS with SOCK_CLOEXEC supported + // But runtime system might not have SOCK_CLOEXEC support + socketFileDescriptor = socket(domain, type, protocol); + } +#else + // Best effort + // Return value is intentionally ignored since socket was successfully opened anyways + fcntl(socketFileDescriptor, F_SETFD, FD_CLOEXEC); +#endif + + return socketFileDescriptor; +} + +JNIEXPORT int JNICALL +NET_SocketPair(int domain, int type, int protocol, int socket_vector[2]) { +#if defined(SOCK_CLOEXEC) + int typeToUse = type | SOCK_CLOEXEC; +#else + int typeToUse = type; +#endif + + int socketFileDescriptor = socketpair(domain, typeToUse, protocol, socket_vector); +#if defined(SOCK_CLOEXEC) + if ((socketFileDescriptor == -1) && (errno = EINVAL)) { + // Attempt to open the socket without SOCK_CLOEXEC + // May have been compiled on an OS with SOCK_CLOEXEC supported + // But runtime system might not have SOCK_CLOEXEC support + socketFileDescriptor = socketpair(domain, type, protocol, socket_vector); + } +#else + // Best effort + // Return value is intentionally ignored since socket was successfully opened anyways + fcntl(socketFileDescriptor, F_SETFD, FD_CLOEXEC); +#endif + + return socketFileDescriptor; +} + #define RESTARTABLE(_cmd, _result) do { \ do { \ _result = _cmd; \ @@ -295,7 +349,7 @@ SOCKETADDRESS sa; socklen_t sa_len = sizeof(SOCKETADDRESS); - fd = socket(AF_INET6, SOCK_STREAM, 0) ; + fd = NET_Socket(AF_INET6, SOCK_STREAM, 0) ; if (fd < 0) { /* * TODO: We really cant tell since it may be an unrelated error @@ -402,7 +456,7 @@ /* Do a simple dummy call, and try to figure out from that */ int one = 1; int rv, s; - s = socket(PF_INET, SOCK_STREAM, 0); + s = NET_Socket(PF_INET, SOCK_STREAM, 0); if (s < 0) { return JNI_FALSE; } diff -r 95c0644a1c47 src/java.base/unix/native/libnet/net_util_md.h --- a/src/java.base/unix/native/libnet/net_util_md.h Fri Jun 15 17:34:01 2018 -0700 +++ b/src/java.base/unix/native/libnet/net_util_md.h Wed Jul 11 01:46:03 2018 -0700 @@ -89,6 +89,8 @@ int NET_Writev(int s, const struct iovec * vector, int count); int NET_Connect(int s, struct sockaddr *addr, int addrlen); int NET_Accept(int s, struct sockaddr *addr, socklen_t *addrlen); +JNIEXPORT int JNICALL NET_Socket(int domain, int type, int protocol); +JNIEXPORT int JNICALL NET_SocketPair(int domain, int type, int protocol, int socket_vector[2]); int NET_SocketClose(int s); int NET_Dup2(int oldfd, int newfd); int NET_Poll(struct pollfd *ufds, unsigned int nfds, int timeout); diff -r 95c0644a1c47 src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c --- a/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c Fri Jun 15 17:34:01 2018 -0700 +++ b/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c Wed Jul 11 01:46:03 2018 -0700 @@ -67,7 +67,7 @@ Java_sun_nio_ch_FileDispatcherImpl_init(JNIEnv *env, jclass cl) { int sp[2]; - if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) { + if (NET_SocketPair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) { JNU_ThrowIOExceptionWithLastError(env, "socketpair failed"); return; } diff -r 95c0644a1c47 src/java.base/unix/native/libnio/ch/Net.c --- a/src/java.base/unix/native/libnio/ch/Net.c Fri Jun 15 17:34:01 2018 -0700 +++ b/src/java.base/unix/native/libnio/ch/Net.c Wed Jul 11 01:46:03 2018 -0700 @@ -198,7 +198,7 @@ int type = (stream ? SOCK_STREAM : SOCK_DGRAM); int domain = (ipv6_available() && preferIPv6) ? AF_INET6 : AF_INET; - fd = socket(domain, type, 0); + fd = NET_Socket(domain, type, 0); if (fd < 0) { return handleSocketError(env, errno); } From: Alan Bateman > Sent: Wednesday, July 11, 2018 12:12 AM To: Andrew Luo >; Norman Maurer > Cc: Martin Buchholz >; net-dev at openjdk.java.net Subject: Re: [PATCH] SOCK_CLOEXEC for opening sockets This seems to cover the sockets created in libnet but there is also a usage in libnio that will need update. It might be cleaner to name it NET_Socket to be consistent with the other wrappers (NET_Bind, NET_SetSocketOpt, etc.). There are a lot of other file descriptors that you may run into. We use socketpair in a few places, we have file descriptors for epoll and more. It makes me wonder if it would be better to use FD_CLOEXEC consistently. In the Windows port then you'll see that we change the inheritance flag on all newly created SOCKETs, that is because is because we don't have the same opportunity to close inherited handles in the child process that we do on Unix platforms. -Alan On 11/07/2018 07:35, Andrew Luo wrote: I agree, I wasn't aware of the other uses of ::socket in the libnet codebase. Thus, I've added a new common function, NET_SocketOpen that can be used by all the source files in libnet and revised my patch: diff -r 95c0644a1c47 src/java.base/unix/native/libnet/Inet4AddressImpl.c --- a/src/java.base/unix/native/libnet/Inet4AddressImpl.c Fri Jun 15 17:34:01 2018 -0700 +++ b/src/java.base/unix/native/libnet/Inet4AddressImpl.c Tue Jul 10 23:32:21 2018 -0700 @@ -264,7 +264,7 @@ int connect_rv = -1; // open a TCP socket - fd = socket(AF_INET, SOCK_STREAM, 0); + fd = NET_SocketOpen(AF_INET, SOCK_STREAM, 0); if (fd == -1) { // note: if you run out of fds, you may not be able to load // the exception class, and get a NoClassDefFoundError instead. @@ -503,7 +503,7 @@ // Let's try to create a RAW socket to send ICMP packets. // This usually requires "root" privileges, so it's likely to fail. - fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); + fd = NET_SocketOpen(AF_INET, SOCK_RAW, IPPROTO_ICMP); if (fd == -1) { return tcp_ping4(env, &sa, netif, timeout, ttl); } else { diff -r 95c0644a1c47 src/java.base/unix/native/libnet/Inet6AddressImpl.c --- a/src/java.base/unix/native/libnet/Inet6AddressImpl.c Fri Jun 15 17:34:01 2018 -0700 +++ b/src/java.base/unix/native/libnet/Inet6AddressImpl.c Tue Jul 10 23:32:21 2018 -0700 @@ -461,7 +461,7 @@ int connect_rv = -1; // open a TCP socket - fd = socket(AF_INET6, SOCK_STREAM, 0); + fd = NET_SocketOpen(AF_INET6, SOCK_STREAM, 0); if (fd == -1) { // note: if you run out of fds, you may not be able to load // the exception class, and get a NoClassDefFoundError instead. @@ -711,7 +711,7 @@ // Let's try to create a RAW socket to send ICMP packets. // This usually requires "root" privileges, so it's likely to fail. - fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); + fd = NET_SocketOpen(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); if (fd == -1) { return tcp_ping6(env, &sa, netif, timeout, ttl); } else { diff -r 95c0644a1c47 src/java.base/unix/native/libnet/NetworkInterface.c --- a/src/java.base/unix/native/libnet/NetworkInterface.c Fri Jun 15 17:34:01 2018 -0700 +++ b/src/java.base/unix/native/libnet/NetworkInterface.c Tue Jul 10 23:32:21 2018 -0700 @@ -1055,7 +1055,7 @@ static int openSocket(JNIEnv *env, int proto) { int sock; - if ((sock = socket(proto, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_SocketOpen(proto, SOCK_DGRAM, 0)) < 0) { // If EPROTONOSUPPORT is returned it means we don't have // support for this proto so don't throw an exception. if (errno != EPROTONOSUPPORT) { @@ -1078,9 +1078,9 @@ static int openSocketWithFallback(JNIEnv *env, const char *ifname) { int sock; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_SocketOpen(AF_INET, SOCK_DGRAM, 0)) < 0) { if (errno == EPROTONOSUPPORT) { - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_SocketOpen(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; @@ -1315,9 +1315,9 @@ static int openSocketWithFallback(JNIEnv *env, const char *ifname) { int sock; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_SocketOpen(AF_INET, SOCK_DGRAM, 0)) < 0) { if (errno == EPROTONOSUPPORT) { - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_SocketOpen(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; @@ -1590,9 +1590,9 @@ int sock, alreadyV6 = 0; struct lifreq if2; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_SocketOpen(AF_INET, SOCK_DGRAM, 0)) < 0) { if (errno == EPROTONOSUPPORT) { - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_SocketOpen(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; @@ -1616,7 +1616,7 @@ strncpy(if2.lifr_name, ifname, sizeof(if2.lifr_name) - 1); if (ioctl(sock, SIOCGLIFNETMASK, (char *)&if2) < 0) { close(sock); - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_SocketOpen(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; @@ -1941,9 +1941,9 @@ static int openSocketWithFallback(JNIEnv *env, const char *ifname) { int sock; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_SocketOpen(AF_INET, SOCK_DGRAM, 0)) < 0) { if (errno == EPROTONOSUPPORT) { - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_SocketOpen(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; diff -r 95c0644a1c47 src/java.base/unix/native/libnet/PlainSocketImpl.c --- a/src/java.base/unix/native/libnet/PlainSocketImpl.c Fri Jun 15 17:34:01 2018 -0700 +++ b/src/java.base/unix/native/libnet/PlainSocketImpl.c Tue Jul 10 23:32:21 2018 -0700 @@ -178,7 +178,7 @@ return; } - if ((fd = socket(domain, type, 0)) == -1) { + if ((fd = NET_SocketOpen(domain, type, 0)) == -1) { /* note: if you run out of fds, you may not be able to load * the exception class, and get a NoClassDefFoundError * instead. diff -r 95c0644a1c47 src/java.base/unix/native/libnet/SdpSupport.c --- a/src/java.base/unix/native/libnet/SdpSupport.c Fri Jun 15 17:34:01 2018 -0700 +++ b/src/java.base/unix/native/libnet/SdpSupport.c Tue Jul 10 23:32:21 2018 -0700 @@ -57,7 +57,7 @@ #if defined(__solaris__) int domain = ipv6_available() ? AF_INET6 : AF_INET; - s = socket(domain, SOCK_STREAM, PROTO_SDP); + s = NET_SocketOpen(domain, SOCK_STREAM, PROTO_SDP); #elif defined(__linux__) /** * IPv6 not supported by SDP on Linux @@ -66,7 +66,7 @@ JNU_ThrowIOException(env, "IPv6 not supported"); return -1; } - s = socket(AF_INET_SDP, SOCK_STREAM, 0); + s = NET_SocketOpen(AF_INET_SDP, SOCK_STREAM, 0); #else /* not supported on other platforms at this time */ s = -1; diff -r 95c0644a1c47 src/java.base/unix/native/libnet/net_util_md.c --- a/src/java.base/unix/native/libnet/net_util_md.c Fri Jun 15 17:34:01 2018 -0700 +++ b/src/java.base/unix/native/libnet/net_util_md.c Tue Jul 10 23:32:21 2018 -0700 @@ -117,6 +117,34 @@ return defaultIndex; } +/* + * Opens a socket + * On systems where supported, uses SOCK_CLOEXEC where possible + */ +int NET_SocketOpen(int domain, int type, int protocol) { +#if defined(SOCK_CLOEXEC) + int typeToUse = type | SOCK_CLOEXEC; +#else + int typeToUse = type; +#endif + + int socketFileDescriptor = socket(domain, typeToUse, protocol); +#if defined(SOCK_CLOEXEC) + if ((socketFileDescriptor == -1) && (errno = EINVAL)) { + // Attempt to open the socket without SOCK_CLOEXEC + // May have been compiled on an OS with SOCK_CLOEXEC supported + // But runtime system might not have SOCK_CLOEXEC support + socketFileDescriptor = socket(domain, type, protocol); + } +#else + // Best effort + // Return value is intentionally ignored since socket was successfully opened anyways + fcntl(socketFileDescriptor, F_SETFD, FD_CLOEXEC); +#endif + + return socketFileDescriptor; +} + #define RESTARTABLE(_cmd, _result) do { \ do { \ _result = _cmd; \ @@ -295,7 +323,7 @@ SOCKETADDRESS sa; socklen_t sa_len = sizeof(SOCKETADDRESS); - fd = socket(AF_INET6, SOCK_STREAM, 0) ; + fd = NET_SocketOpen(AF_INET6, SOCK_STREAM, 0) ; if (fd < 0) { /* * TODO: We really cant tell since it may be an unrelated error @@ -402,7 +430,7 @@ /* Do a simple dummy call, and try to figure out from that */ int one = 1; int rv, s; - s = socket(PF_INET, SOCK_STREAM, 0); + s = NET_SocketOpen(PF_INET, SOCK_STREAM, 0); if (s < 0) { return JNI_FALSE; } diff -r 95c0644a1c47 src/java.base/unix/native/libnet/net_util_md.h --- a/src/java.base/unix/native/libnet/net_util_md.h Fri Jun 15 17:34:01 2018 -0700 +++ b/src/java.base/unix/native/libnet/net_util_md.h Tue Jul 10 23:32:21 2018 -0700 @@ -89,6 +89,7 @@ int NET_Writev(int s, const struct iovec * vector, int count); int NET_Connect(int s, struct sockaddr *addr, int addrlen); int NET_Accept(int s, struct sockaddr *addr, socklen_t *addrlen); +int NET_SocketOpen(int domain, int type, int protocol); int NET_SocketClose(int s); int NET_Dup2(int oldfd, int newfd); int NET_Poll(struct pollfd *ufds, unsigned int nfds, int timeout); From: Norman Maurer Sent: Tuesday, July 10, 2018 9:55 AM To: Alan Bateman Cc: Martin Buchholz ; Andrew Luo ; net-dev at openjdk.java.net Subject: Re: [PATCH] SOCK_CLOEXEC for opening sockets +1 I think this makes a lot of sense On 10. Jul 2018, at 17:54, Alan Bateman > wrote: On 10/07/2018 17:40, Martin Buchholz wrote: I agree with this approach - it parallels the efforts made with O_CLOEXEC in past years. According to https://www.freebsd.org/cgi/man.cgi?query=socket&sektion=2 SOCK_CLOEXEC is also available on freebsd. This is something that doesn't come up too often, I assume because most developers using ProcessBuilder/Process rather than invoking fork from native code. If we are going to tackle this issue then it will require changes in several places, changing PlainSocketImpl.c is just one of several. -Alan -------------- next part -------------- An HTML attachment was scrubbed... URL: From Alan.Bateman at oracle.com Thu Jul 12 06:59:04 2018 From: Alan.Bateman at oracle.com (Alan Bateman) Date: Thu, 12 Jul 2018 07:59:04 +0100 Subject: [PATCH] SOCK_CLOEXEC for opening sockets In-Reply-To: References: <0c24795d-350e-3ac8-4417-0480b41c5c9c@oracle.com> Message-ID: <83f34e37-5cb6-832d-2858-26377d1c8e9d@oracle.com> On 12/07/2018 05:55, Andrew Luo wrote: > > Ok, fixed a few more places (and a bug where fcntl was being run on a > -1 fd).? Patch is below, let me know if there?s any other suggestions/etc. > The file system code should not be calling into NET_* functions. The changes to net_util_* will also need cleanup. Otherwise I think you've got all the places in the networking / NIO APIs, at least on Linux. There are others on macOS, Solaris, ... of course. That said,? I assume we have many more places in the JDK that have file descriptors to open files and other resources. If we really want to support the case of someone calling fork/exec from JNI code then it will likely need work in several other areas. -Alan -------------- next part -------------- An HTML attachment was scrubbed... URL: From andrewluotechnologies at outlook.com Thu Jul 12 07:21:05 2018 From: andrewluotechnologies at outlook.com (Andrew Luo) Date: Thu, 12 Jul 2018 07:21:05 +0000 Subject: [PATCH] SOCK_CLOEXEC for opening sockets In-Reply-To: <83f34e37-5cb6-832d-2858-26377d1c8e9d@oracle.com> References: <0c24795d-350e-3ac8-4417-0480b41c5c9c@oracle.com> <83f34e37-5cb6-832d-2858-26377d1c8e9d@oracle.com> Message-ID: Thanks, I can refactor it. I'm not as familiar with the OpenJDK architecture - should I just duplicate the function into libnio or is there some common utility library that I should move it into? Also, let me know what in net_util_* needs cleanup. The other instances of socket/socketpair in Mac/AIX/Solaris I'm willing to handle as well. Files are mostly already handled: https://bugs.openjdk.java.net/browse/JDK-8043780 (in a similar way - O_CLOEXEC on systems that support it and fcntl on other POSIX systems). One other resource you mentioned is epolls. Perhaps there's also other file descriptors that are being used elsewhere, but I think it will take me longer time to figure out. I'm willing to work on that as well if we all think it's a good idea. Anyways, while I agree that it would be ideal to address those other file descriptors as well, is it ok to address those in a separate changeset, or do you think that this changeset doesn't really provide value unless we make this change everywhere? Sockets are somewhat more problematic than other types of file descriptors (in my opinion) as if you use it to listen on a port and then fork child processes (from native code) then restart the parent process, it won't be able to listen to the same port until all of the children processes (of the previous process) exit/close the fd. Other file descriptors, unless you open in exclusive mode, won't have the same problem (although the behavior is undesirable). Thanks, -Andrew From: Alan Bateman Sent: Wednesday, July 11, 2018 11:59 PM To: Andrew Luo Cc: Martin Buchholz ; net-dev at openjdk.java.net Subject: Re: [PATCH] SOCK_CLOEXEC for opening sockets On 12/07/2018 05:55, Andrew Luo wrote: Ok, fixed a few more places (and a bug where fcntl was being run on a -1 fd). Patch is below, let me know if there's any other suggestions/etc. The file system code should not be calling into NET_* functions. The changes to net_util_* will also need cleanup. Otherwise I think you've got all the places in the networking / NIO APIs, at least on Linux. There are others on macOS, Solaris, ... of course. That said, I assume we have many more places in the JDK that have file descriptors to open files and other resources. If we really want to support the case of someone calling fork/exec from JNI code then it will likely need work in several other areas. -Alan -------------- next part -------------- An HTML attachment was scrubbed... URL: From Alan.Bateman at oracle.com Mon Jul 16 07:33:04 2018 From: Alan.Bateman at oracle.com (Alan Bateman) Date: Mon, 16 Jul 2018 08:33:04 +0100 Subject: [PATCH] SOCK_CLOEXEC for opening sockets In-Reply-To: References: <0c24795d-350e-3ac8-4417-0480b41c5c9c@oracle.com> <83f34e37-5cb6-832d-2858-26377d1c8e9d@oracle.com> Message-ID: <6e82becf-5930-e8f2-b101-6a0c99e43a37@oracle.com> On 12/07/2018 08:21, Andrew Luo wrote: > > Thanks, I can refactor it.? I?m not as familiar with the OpenJDK > architecture ? should I just duplicate the function into libnio or is > there some common utility library that I should move it into?? Also, > let me know what in net_util_* needs cleanup.? The other instances of > socket/socketpair in Mac/AIX/Solaris I?m willing to handle as well. > > Files are mostly already handled: > https://bugs.openjdk.java.net/browse/JDK-8043780 (in a similar way ? > O_CLOEXEC on systems that support it and fcntl on other POSIX > systems).? One other resource you mentioned is epolls.? Perhaps > there?s also other file descriptors that are being used elsewhere, but > I think it will take me longer time to figure out.? I?m willing to > work on that as well if we all think it?s a good idea. > JDK-8043780 was in libjvm so it doesn't cover file and networking I/O or other file descriptors created in the libraries. I agree with your comment that this could be done in steps as there are many areas of the libraries that would changes to work with code that uses fork/exec directly rather than ProcessBuilder/Process. It's okay to start with the socket and channel APIs (native code in libnet and libnio). -Alan. -------------- next part -------------- An HTML attachment was scrubbed... URL: From chris.hegarty at oracle.com Mon Jul 16 09:57:57 2018 From: chris.hegarty at oracle.com (Chris Hegarty) Date: Mon, 16 Jul 2018 10:57:57 +0100 Subject: [PATCH] SOCK_CLOEXEC for opening sockets In-Reply-To: References: <0c24795d-350e-3ac8-4417-0480b41c5c9c@oracle.com> <83f34e37-5cb6-832d-2858-26377d1c8e9d@oracle.com> Message-ID: <3f50f583-a990-fb70-da1d-df2c7b26e08e@oracle.com> Andrew, I filed the following issue to track this: https://bugs.openjdk.java.net/browse/JDK-8207335 Once you produce an updated patch, I can review and sponsor this for you. -Chris. On 12/07/18 08:21, Andrew Luo wrote: > Thanks, I can refactor it.? I?m not as familiar with the OpenJDK > architecture ? should I just duplicate the function into libnio or is > there some common utility library that I should move it into?? Also, let > me know what in net_util_* needs cleanup.? The other instances of > socket/socketpair in Mac/AIX/Solaris I?m willing to handle as well. > > Files are mostly already handled: > https://bugs.openjdk.java.net/browse/JDK-8043780 (in a similar way ? > O_CLOEXEC on systems that support it and fcntl on other POSIX systems). > One other resource you mentioned is epolls.? Perhaps there?s also other > file descriptors that are being used elsewhere, but I think it will take > me longer time to figure out.? I?m willing to work on that as well if we > all think it?s a good idea. > > Anyways, while I agree that it would be ideal to address those other > file descriptors as well, is it ok to address those in a separate > changeset, or do you think that this changeset doesn?t really provide > value unless we make this change everywhere?? Sockets are somewhat more > problematic than other types of file descriptors (in my opinion) as if > you use it to listen on a port and then fork child processes (from > native code) then restart the parent process, it won?t be able to listen > to the same port until all of the children processes (of the previous > process) exit/close the fd.? Other file descriptors, unless you open in > exclusive mode, won?t have the same problem (although the behavior is > undesirable). > > Thanks, > > -Andrew > > *From:*Alan Bateman > *Sent:* Wednesday, July 11, 2018 11:59 PM > *To:* Andrew Luo > *Cc:* Martin Buchholz ; net-dev at openjdk.java.net > *Subject:* Re: [PATCH] SOCK_CLOEXEC for opening sockets > > On 12/07/2018 05:55, Andrew Luo wrote: > > Ok, fixed a few more places (and a bug where fcntl was being run on > a -1 fd).? Patch is below, let me know if there?s any other > suggestions/etc. > > The file system code should not be calling into NET_* functions.? The > changes to net_util_* will also need cleanup. Otherwise I think you've > got all the places in the networking / NIO APIs, at least on Linux. > There are others on macOS, Solaris, ... of course. > > That said,? I assume we have many more places in the JDK that have file > descriptors to open files and other resources. If we really want to > support the case of someone calling fork/exec from JNI code then it will > likely need work in several other areas. > > -Alan > From chris.hegarty at oracle.com Mon Jul 16 11:10:12 2018 From: chris.hegarty at oracle.com (Chris Hegarty) Date: Mon, 16 Jul 2018 12:10:12 +0100 Subject: RFR [11] 8207265: Bad HTML in {@link} in HttpResponse.BodySubscribers.ofPublisher Message-ID: <7dd7dc8e-03a5-df18-9a4b-ef8aca32f630@oracle.com> This is a review request for a small doc-only change to fix a "bad" use of angle brackets ( for a parameterized type ) as the target of an @link [*]. The simplest solution is to just replace the link with @code, since the built javadoc contains the appropriate links in the method declaration. diff --git a/src/java.net.http/share/classes/java/net/http/HttpResponse.java b/src/java.net.http/share/classes/java/net/http/HttpResponse.java --- a/src/java.net.http/share/classes/java/net/http/HttpResponse.java +++ b/src/java.net.http/share/classes/java/net/http/HttpResponse.java @@ -1188,7 +1188,7 @@ /** * Returns a response subscriber which publishes the response body - * through a {@link Publisher Publisher>}. + * through a {@code Publisher>}. * *

The {@link HttpResponse} using this subscriber is available * immediately after the response headers have been read, without -Chris. [*] https://bugs.openjdk.java.net/browse/JDK-8207265 From michael.x.mcmahon at oracle.com Mon Jul 16 11:16:04 2018 From: michael.x.mcmahon at oracle.com (Michael McMahon) Date: Mon, 16 Jul 2018 12:16:04 +0100 Subject: RFR [11] 8207265: Bad HTML in {@link} in HttpResponse.BodySubscribers.ofPublisher In-Reply-To: <7dd7dc8e-03a5-df18-9a4b-ef8aca32f630@oracle.com> References: <7dd7dc8e-03a5-df18-9a4b-ef8aca32f630@oracle.com> Message-ID: <5B4C7E74.6040507@oracle.com> Looks fine Chris. - Michael. On 16/07/2018, 12:10, Chris Hegarty wrote: > This is a review request for a small doc-only change to fix a > "bad" use of angle brackets ( for a parameterized type ) as > the target of an @link [*]. The simplest solution is to just > replace the link with @code, since the built javadoc contains > the appropriate links in the method declaration. > > > diff --git > a/src/java.net.http/share/classes/java/net/http/HttpResponse.java > b/src/java.net.http/share/classes/java/net/http/HttpResponse.java > --- a/src/java.net.http/share/classes/java/net/http/HttpResponse.java > +++ b/src/java.net.http/share/classes/java/net/http/HttpResponse.java > @@ -1188,7 +1188,7 @@ > > /** > * Returns a response subscriber which publishes the response > body > - * through a {@link Publisher Publisher>}. > + * through a {@code Publisher>}. > * > *

The {@link HttpResponse} using this subscriber is > available > * immediately after the response headers have been read, > without > > > -Chris. > > [*] https://bugs.openjdk.java.net/browse/JDK-8207265 From andrewluotechnologies at outlook.com Tue Jul 17 06:33:52 2018 From: andrewluotechnologies at outlook.com (Andrew Luo) Date: Tue, 17 Jul 2018 06:33:52 +0000 Subject: [PATCH] SOCK_CLOEXEC for opening sockets In-Reply-To: <3f50f583-a990-fb70-da1d-df2c7b26e08e@oracle.com> References: <0c24795d-350e-3ac8-4417-0480b41c5c9c@oracle.com> <83f34e37-5cb6-832d-2858-26377d1c8e9d@oracle.com> <3f50f583-a990-fb70-da1d-df2c7b26e08e@oracle.com> Message-ID: Great, thanks. By the way, I do see other places where we use NET_* functions in libnio, but if you prefer that I duplicate that code instead, I can do that. By the way, I do see other places where libnio calls into the NET_* functions: jdk/src/java.base/unix/native/libnio$ grep -F -r --include='*.c' 'NET_' . ./ch/DatagramChannelImpl.c: if (!NET_SockaddrEqualsInetAddress(env, &sa, senderAddr)) { ./ch/DatagramChannelImpl.c: if (port != NET_GetPortFromSockaddr(&sa)) { ./ch/DatagramChannelImpl.c: jobject ia = NET_SockaddrToInetAddress(env, &sa, &port); ./ch/DatagramChannelImpl.c: NET_GetPortFromSockaddr(&sa)); ./ch/DatagramChannelImpl.c: if (NET_InetAddressToSockaddr(env, destAddress, destPort, &sa, ./ch/Net.c: fd = NET_Socket(domain, type, 0); ./ch/Net.c: if (NET_InetAddressToSockaddr(env, iao, port, &sa, &sa_len, ./ch/Net.c: rv = NET_Bind(fdval(env, fdo), &sa, sa_len); ./ch/Net.c: if (NET_InetAddressToSockaddr(env, iao, port, &sa, &sa_len, preferIPv6) != 0) { ./ch/Net.c: return NET_GetPortFromSockaddr(&sa); ./ch/Net.c: return NET_SockaddrToInetAddress(env, &sa, &port); ./ch/Net.c: n = NET_GetSockOpt(fdval(env, fdo), level, opt, arg, (int*)&arglen); ./ch/Net.c: n = NET_SetSockOpt(fdval(env, fdo), level, opt, parg, arglen); ./ch/ServerSocketChannelImpl.c: remote_ia = NET_SockaddrToInetAddress(env, &sa, (int *)&remote_port); ./ch/InheritedChannel.c: /* Initialize InetAddress IDs before later use of NET_XXX functions */ ./ch/InheritedChannel.c: remote_ia = NET_SockaddrToInetAddress(env, &sa, (int *)&remote_port); ./ch/InheritedChannel.c: NET_SockaddrToInetAddress(env, &sa, (int *)&remote_port); ./ch/FileDispatcherImpl.c: if (NET_SocketPair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) { Here's my updated patch: diff --git a/make/lib/Lib-jdk.net.gmk b/make/lib/Lib-jdk.net.gmk --- a/make/lib/Lib-jdk.net.gmk +++ b/make/lib/Lib-jdk.net.gmk @@ -35,7 +35,7 @@ CFLAGS := $(CFLAGS_JDKLIB), \ LDFLAGS := $(LDFLAGS_JDKLIB) \ $(call SET_SHARED_LIBRARY_ORIGIN), \ - LIBS := -ljava, \ + LIBS := -ljava -lnet, \ LIBS_solaris := -lsocket, \ LIBS_linux := -ljvm, \ )) diff --git a/src/java.base/aix/native/libnio/ch/AixPollPort.c b/src/java.base/aix/native/libnio/ch/AixPollPort.c --- a/src/java.base/aix/native/libnio/ch/AixPollPort.c +++ b/src/java.base/aix/native/libnio/ch/AixPollPort.c @@ -137,7 +137,7 @@ JNIEXPORT void JNICALL Java_sun_nio_ch_AixPollPort_socketpair(JNIEnv* env, jclass clazz, jintArray sv) { int sp[2]; - if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) == -1) { + if (NET_SocketPair(PF_UNIX, SOCK_STREAM, 0, sp) == -1) { JNU_ThrowIOExceptionWithLastError(env, "socketpair failed"); } else { jint res[2]; diff --git a/src/java.base/linux/native/libnio/fs/LinuxWatchService.c b/src/java.base/linux/native/libnio/fs/LinuxWatchService.c --- a/src/java.base/linux/native/libnio/fs/LinuxWatchService.c +++ b/src/java.base/linux/native/libnio/fs/LinuxWatchService.c @@ -119,7 +119,7 @@ (JNIEnv* env, jclass clazz, jintArray sv) { int sp[2]; - if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) == -1) { + if (NET_SocketPair(PF_UNIX, SOCK_STREAM, 0, sp) == -1) { throwUnixException(env, errno); } else { jint res[2]; diff --git a/src/java.base/unix/native/libnet/Inet4AddressImpl.c b/src/java.base/unix/native/libnet/Inet4AddressImpl.c --- a/src/java.base/unix/native/libnet/Inet4AddressImpl.c +++ b/src/java.base/unix/native/libnet/Inet4AddressImpl.c @@ -264,7 +264,7 @@ int connect_rv = -1; // open a TCP socket - fd = socket(AF_INET, SOCK_STREAM, 0); + fd = NET_Socket(AF_INET, SOCK_STREAM, 0); if (fd == -1) { // note: if you run out of fds, you may not be able to load // the exception class, and get a NoClassDefFoundError instead. @@ -503,7 +503,7 @@ // Let's try to create a RAW socket to send ICMP packets. // This usually requires "root" privileges, so it's likely to fail. - fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); + fd = NET_Socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); if (fd == -1) { return tcp_ping4(env, &sa, netif, timeout, ttl); } else { diff --git a/src/java.base/unix/native/libnet/Inet6AddressImpl.c b/src/java.base/unix/native/libnet/Inet6AddressImpl.c --- a/src/java.base/unix/native/libnet/Inet6AddressImpl.c +++ b/src/java.base/unix/native/libnet/Inet6AddressImpl.c @@ -461,7 +461,7 @@ int connect_rv = -1; // open a TCP socket - fd = socket(AF_INET6, SOCK_STREAM, 0); + fd = NET_Socket(AF_INET6, SOCK_STREAM, 0); if (fd == -1) { // note: if you run out of fds, you may not be able to load // the exception class, and get a NoClassDefFoundError instead. @@ -711,7 +711,7 @@ // Let's try to create a RAW socket to send ICMP packets. // This usually requires "root" privileges, so it's likely to fail. - fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); + fd = NET_Socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); if (fd == -1) { return tcp_ping6(env, &sa, netif, timeout, ttl); } else { diff --git a/src/java.base/unix/native/libnet/NetworkInterface.c b/src/java.base/unix/native/libnet/NetworkInterface.c --- a/src/java.base/unix/native/libnet/NetworkInterface.c +++ b/src/java.base/unix/native/libnet/NetworkInterface.c @@ -1055,7 +1055,7 @@ static int openSocket(JNIEnv *env, int proto) { int sock; - if ((sock = socket(proto, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(proto, SOCK_DGRAM, 0)) < 0) { // If EPROTONOSUPPORT is returned it means we don't have // support for this proto so don't throw an exception. if (errno != EPROTONOSUPPORT) { @@ -1078,9 +1078,9 @@ static int openSocketWithFallback(JNIEnv *env, const char *ifname) { int sock; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) { if (errno == EPROTONOSUPPORT) { - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; @@ -1315,9 +1315,9 @@ static int openSocketWithFallback(JNIEnv *env, const char *ifname) { int sock; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) { if (errno == EPROTONOSUPPORT) { - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; @@ -1590,9 +1590,9 @@ int sock, alreadyV6 = 0; struct lifreq if2; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) { if (errno == EPROTONOSUPPORT) { - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; @@ -1616,7 +1616,7 @@ strncpy(if2.lifr_name, ifname, sizeof(if2.lifr_name) - 1); if (ioctl(sock, SIOCGLIFNETMASK, (char *)&if2) < 0) { close(sock); - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; @@ -1941,9 +1941,9 @@ static int openSocketWithFallback(JNIEnv *env, const char *ifname) { int sock; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) { if (errno == EPROTONOSUPPORT) { - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; diff --git a/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c b/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c --- a/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c +++ b/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c @@ -904,7 +904,7 @@ return; } - if ((fd = socket(domain, SOCK_DGRAM, 0)) == -1) { + if ((fd = NET_Socket(domain, SOCK_DGRAM, 0)) == -1) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "Error creating socket"); return; diff --git a/src/java.base/unix/native/libnet/PlainSocketImpl.c b/src/java.base/unix/native/libnet/PlainSocketImpl.c --- a/src/java.base/unix/native/libnet/PlainSocketImpl.c +++ b/src/java.base/unix/native/libnet/PlainSocketImpl.c @@ -77,7 +77,7 @@ int sv[2]; #ifdef AF_UNIX - if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == -1) { + if (NET_SocketPair(AF_UNIX, SOCK_STREAM, 0, sv) == -1) { return -1; } #else @@ -178,7 +178,7 @@ return; } - if ((fd = socket(domain, type, 0)) == -1) { + if ((fd = NET_Socket(domain, type, 0)) == -1) { /* note: if you run out of fds, you may not be able to load * the exception class, and get a NoClassDefFoundError * instead. diff --git a/src/java.base/unix/native/libnet/SdpSupport.c b/src/java.base/unix/native/libnet/SdpSupport.c --- a/src/java.base/unix/native/libnet/SdpSupport.c +++ b/src/java.base/unix/native/libnet/SdpSupport.c @@ -57,7 +57,7 @@ #if defined(__solaris__) int domain = ipv6_available() ? AF_INET6 : AF_INET; - s = socket(domain, SOCK_STREAM, PROTO_SDP); + s = NET_Socket(domain, SOCK_STREAM, PROTO_SDP); #elif defined(__linux__) /** * IPv6 not supported by SDP on Linux @@ -66,7 +66,7 @@ JNU_ThrowIOException(env, "IPv6 not supported"); return -1; } - s = socket(AF_INET_SDP, SOCK_STREAM, 0); + s = NET_Socket(AF_INET_SDP, SOCK_STREAM, 0); #else /* not supported on other platforms at this time */ s = -1; diff --git a/src/java.base/unix/native/libnet/net_util_md.c b/src/java.base/unix/native/libnet/net_util_md.c --- a/src/java.base/unix/native/libnet/net_util_md.c +++ b/src/java.base/unix/native/libnet/net_util_md.c @@ -117,6 +117,64 @@ return defaultIndex; } +/* + * Opens a socket + * On systems where supported, uses SOCK_CLOEXEC where possible + */ +JNIEXPORT int JNICALL +NET_Socket(int domain, int type, int protocol) { +#if defined(SOCK_CLOEXEC) + int typeToUse = type | SOCK_CLOEXEC; +#else + int typeToUse = type; +#endif + + int socketFileDescriptor = socket(domain, typeToUse, protocol); +#if defined(SOCK_CLOEXEC) + if ((socketFileDescriptor == -1) && (errno = EINVAL)) { + // Attempt to open the socket without SOCK_CLOEXEC + // May have been compiled on an OS with SOCK_CLOEXEC supported + // But runtime system might not have SOCK_CLOEXEC support + socketFileDescriptor = socket(domain, type, protocol); + } +#else + if (socketFileDescriptor != -1) { + // Best effort + // Return value is intentionally ignored since socket was successfully opened anyways + fcntl(socketFileDescriptor, F_SETFD, FD_CLOEXEC); + } +#endif + + return socketFileDescriptor; +} + +JNIEXPORT int JNICALL +NET_SocketPair(int domain, int type, int protocol, int socket_vector[2]) { +#if defined(SOCK_CLOEXEC) + int typeToUse = type | SOCK_CLOEXEC; +#else + int typeToUse = type; +#endif + + int socketFileDescriptor = socketpair(domain, typeToUse, protocol, socket_vector); +#if defined(SOCK_CLOEXEC) + if ((socketFileDescriptor == -1) && (errno = EINVAL)) { + // Attempt to open the socket without SOCK_CLOEXEC + // May have been compiled on an OS with SOCK_CLOEXEC supported + // But runtime system might not have SOCK_CLOEXEC support + socketFileDescriptor = socketpair(domain, type, protocol, socket_vector); + } +#else + if (socketFileDescriptor != -1) { + // Best effort + // Return value is intentionally ignored since socket was successfully opened anyways + fcntl(socketFileDescriptor, F_SETFD, FD_CLOEXEC); + } +#endif + + return socketFileDescriptor; +} + #define RESTARTABLE(_cmd, _result) do { \ do { \ _result = _cmd; \ @@ -295,7 +353,7 @@ SOCKETADDRESS sa; socklen_t sa_len = sizeof(SOCKETADDRESS); - fd = socket(AF_INET6, SOCK_STREAM, 0) ; + fd = NET_Socket(AF_INET6, SOCK_STREAM, 0) ; if (fd < 0) { /* * TODO: We really cant tell since it may be an unrelated error @@ -402,7 +460,7 @@ /* Do a simple dummy call, and try to figure out from that */ int one = 1; int rv, s; - s = socket(PF_INET, SOCK_STREAM, 0); + s = NET_Socket(PF_INET, SOCK_STREAM, 0); if (s < 0) { return JNI_FALSE; } diff --git a/src/java.base/unix/native/libnet/net_util_md.h b/src/java.base/unix/native/libnet/net_util_md.h --- a/src/java.base/unix/native/libnet/net_util_md.h +++ b/src/java.base/unix/native/libnet/net_util_md.h @@ -89,6 +89,8 @@ int NET_Writev(int s, const struct iovec * vector, int count); int NET_Connect(int s, struct sockaddr *addr, int addrlen); int NET_Accept(int s, struct sockaddr *addr, socklen_t *addrlen); +JNIEXPORT int JNICALL NET_Socket(int domain, int type, int protocol); +JNIEXPORT int JNICALL NET_SocketPair(int domain, int type, int protocol, int socket_vector[2]); int NET_SocketClose(int s); int NET_Dup2(int oldfd, int newfd); int NET_Poll(struct pollfd *ufds, unsigned int nfds, int timeout); diff --git a/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c b/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c --- a/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c +++ b/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c @@ -67,7 +67,7 @@ Java_sun_nio_ch_FileDispatcherImpl_init(JNIEnv *env, jclass cl) { int sp[2]; - if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) { + if (NET_SocketPair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) { JNU_ThrowIOExceptionWithLastError(env, "socketpair failed"); return; } diff --git a/src/java.base/unix/native/libnio/ch/Net.c b/src/java.base/unix/native/libnio/ch/Net.c --- a/src/java.base/unix/native/libnio/ch/Net.c +++ b/src/java.base/unix/native/libnio/ch/Net.c @@ -198,7 +198,7 @@ int type = (stream ? SOCK_STREAM : SOCK_DGRAM); int domain = (ipv6_available() && preferIPv6) ? AF_INET6 : AF_INET; - fd = socket(domain, type, 0); + fd = NET_Socket(domain, type, 0); if (fd < 0) { return handleSocketError(env, errno); } diff --git a/src/jdk.net/linux/native/libextnet/LinuxSocketOptions.c b/src/jdk.net/linux/native/libextnet/LinuxSocketOptions.c --- a/src/jdk.net/linux/native/libextnet/LinuxSocketOptions.c +++ b/src/jdk.net/linux/native/libextnet/LinuxSocketOptions.c @@ -86,7 +86,7 @@ (JNIEnv *env, jobject unused) { int one = 1; int rv, s; - s = socket(PF_INET, SOCK_STREAM, 0); + s = NET_Socket(PF_INET, SOCK_STREAM, 0); if (s < 0) { return JNI_FALSE; } @@ -103,7 +103,7 @@ static jint socketOptionSupported(jint sockopt) { jint one = 1; jint rv, s; - s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + s = NET_Socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (s < 0) { return 0; } diff --git a/src/jdk.net/macosx/native/libextnet/MacOSXSocketOptions.c b/src/jdk.net/macosx/native/libextnet/MacOSXSocketOptions.c --- a/src/jdk.net/macosx/native/libextnet/MacOSXSocketOptions.c +++ b/src/jdk.net/macosx/native/libextnet/MacOSXSocketOptions.c @@ -35,7 +35,7 @@ static jint socketOptionSupported(jint sockopt) { jint one = 1; jint rv, s; - s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + s = NET_Socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (s < 0) { return 0; } diff --git a/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.c b/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.c --- a/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.c +++ b/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.c @@ -157,7 +157,7 @@ sock_flow_props_t props; int rv, s; - s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + s = NET_Socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (s < 0) { return JNI_FALSE; } diff --git a/src/jdk.sctp/unix/native/libsctp/SctpNet.c b/src/jdk.sctp/unix/native/libsctp/SctpNet.c --- a/src/jdk.sctp/unix/native/libsctp/SctpNet.c +++ b/src/jdk.sctp/unix/native/libsctp/SctpNet.c @@ -151,7 +151,7 @@ Java_sun_nio_ch_sctp_SctpNet_init (JNIEnv *env, jclass cl) { int sp[2]; - if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) { + if (NET_SocketPair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) { JNU_ThrowIOExceptionWithLastError(env, "socketpair failed"); return; } @@ -180,7 +180,7 @@ return 0; } - fd = socket(domain, (oneToOne ? SOCK_STREAM : SOCK_SEQPACKET), IPPROTO_SCTP); + fd = NET_Socket(domain, (oneToOne ? SOCK_STREAM : SOCK_SEQPACKET), IPPROTO_SCTP); if (fd < 0) { return handleSocketError(env, errno); By the way, I only have x86 systems (and VMs) - any way I can test this on AIX, or what is the preferred way to ensure my changes will build properly on all platforms? Thanks, -Andrew -----Original Message----- From: Chris Hegarty Sent: Monday, July 16, 2018 2:58 AM To: Andrew Luo Cc: net-dev at openjdk.java.net Subject: Re: [PATCH] SOCK_CLOEXEC for opening sockets Andrew, I filed the following issue to track this: https://bugs.openjdk.java.net/browse/JDK-8207335 Once you produce an updated patch, I can review and sponsor this for you. -Chris. On 12/07/18 08:21, Andrew Luo wrote: > Thanks, I can refactor it.? I'm not as familiar with the OpenJDK > architecture - should I just duplicate the function into libnio or is > there some common utility library that I should move it into?? Also, > let me know what in net_util_* needs cleanup.? The other instances of > socket/socketpair in Mac/AIX/Solaris I'm willing to handle as well. > > Files are mostly already handled: > https://bugs.openjdk.java.net/browse/JDK-8043780 (in a similar way - > O_CLOEXEC on systems that support it and fcntl on other POSIX systems). > One other resource you mentioned is epolls.? Perhaps there's also > other file descriptors that are being used elsewhere, but I think it > will take me longer time to figure out.? I'm willing to work on that > as well if we all think it's a good idea. > > Anyways, while I agree that it would be ideal to address those other > file descriptors as well, is it ok to address those in a separate > changeset, or do you think that this changeset doesn't really provide > value unless we make this change everywhere?? Sockets are somewhat > more problematic than other types of file descriptors (in my opinion) > as if you use it to listen on a port and then fork child processes > (from native code) then restart the parent process, it won't be able > to listen to the same port until all of the children processes (of the > previous > process) exit/close the fd.? Other file descriptors, unless you open > in exclusive mode, won't have the same problem (although the behavior > is undesirable). > > Thanks, > > -Andrew > > *From:*Alan Bateman > *Sent:* Wednesday, July 11, 2018 11:59 PM > *To:* Andrew Luo > *Cc:* Martin Buchholz ; net-dev at openjdk.java.net > *Subject:* Re: [PATCH] SOCK_CLOEXEC for opening sockets > > On 12/07/2018 05:55, Andrew Luo wrote: > > Ok, fixed a few more places (and a bug where fcntl was being run on > a -1 fd).? Patch is below, let me know if there's any other > suggestions/etc. > > The file system code should not be calling into NET_* functions.? The > changes to net_util_* will also need cleanup. Otherwise I think you've > got all the places in the networking / NIO APIs, at least on Linux. > There are others on macOS, Solaris, ... of course. > > That said,? I assume we have many more places in the JDK that have > file descriptors to open files and other resources. If we really want > to support the case of someone calling fork/exec from JNI code then it > will likely need work in several other areas. > > -Alan > From Alan.Bateman at oracle.com Tue Jul 17 06:41:10 2018 From: Alan.Bateman at oracle.com (Alan Bateman) Date: Tue, 17 Jul 2018 07:41:10 +0100 Subject: [PATCH] SOCK_CLOEXEC for opening sockets In-Reply-To: References: <0c24795d-350e-3ac8-4417-0480b41c5c9c@oracle.com> <83f34e37-5cb6-832d-2858-26377d1c8e9d@oracle.com> <3f50f583-a990-fb70-da1d-df2c7b26e08e@oracle.com> Message-ID: <6d445479-e05e-1dcc-fe25-81ee17acb219@oracle.com> On 17/07/2018 07:33, Andrew Luo wrote: > Great, thanks. > > By the way, I do see other places where we use NET_* functions in libnio, but if you prefer that I duplicate that code instead, It's okay for the code in libnio/ch to use the NET_* functions. The issue is the changes to libnio/fs which is the file system code as that should have no dependences on functions exported by libnet. I think it would be better to drop the changes to the fs code in this patch. As we've been discussing, there are dozens of other areas that will work to allow fork/exec work reliably in native code, I think the networking and channels area is just the first step. -Alan From andrewluotechnologies at outlook.com Tue Jul 17 06:58:33 2018 From: andrewluotechnologies at outlook.com (Andrew Luo) Date: Tue, 17 Jul 2018 06:58:33 +0000 Subject: [PATCH] SOCK_CLOEXEC for opening sockets In-Reply-To: <6d445479-e05e-1dcc-fe25-81ee17acb219@oracle.com> References: <0c24795d-350e-3ac8-4417-0480b41c5c9c@oracle.com> <83f34e37-5cb6-832d-2858-26377d1c8e9d@oracle.com> <3f50f583-a990-fb70-da1d-df2c7b26e08e@oracle.com> <6d445479-e05e-1dcc-fe25-81ee17acb219@oracle.com> Message-ID: Thanks for the feedback. Made those changes (reverted src/java.base/linux/native/libnio/fs/LinuxWatchService.c): diff --git a/make/lib/Lib-jdk.net.gmk b/make/lib/Lib-jdk.net.gmk --- a/make/lib/Lib-jdk.net.gmk +++ b/make/lib/Lib-jdk.net.gmk @@ -35,7 +35,7 @@ CFLAGS := $(CFLAGS_JDKLIB), \ LDFLAGS := $(LDFLAGS_JDKLIB) \ $(call SET_SHARED_LIBRARY_ORIGIN), \ - LIBS := -ljava, \ + LIBS := -ljava -lnet, \ LIBS_solaris := -lsocket, \ LIBS_linux := -ljvm, \ )) diff --git a/src/java.base/aix/native/libnio/ch/AixPollPort.c b/src/java.base/aix/native/libnio/ch/AixPollPort.c --- a/src/java.base/aix/native/libnio/ch/AixPollPort.c +++ b/src/java.base/aix/native/libnio/ch/AixPollPort.c @@ -137,7 +137,7 @@ JNIEXPORT void JNICALL Java_sun_nio_ch_AixPollPort_socketpair(JNIEnv* env, jclass clazz, jintArray sv) { int sp[2]; - if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) == -1) { + if (NET_SocketPair(PF_UNIX, SOCK_STREAM, 0, sp) == -1) { JNU_ThrowIOExceptionWithLastError(env, "socketpair failed"); } else { jint res[2]; diff --git a/src/java.base/unix/native/libnet/Inet4AddressImpl.c b/src/java.base/unix/native/libnet/Inet4AddressImpl.c --- a/src/java.base/unix/native/libnet/Inet4AddressImpl.c +++ b/src/java.base/unix/native/libnet/Inet4AddressImpl.c @@ -264,7 +264,7 @@ int connect_rv = -1; // open a TCP socket - fd = socket(AF_INET, SOCK_STREAM, 0); + fd = NET_Socket(AF_INET, SOCK_STREAM, 0); if (fd == -1) { // note: if you run out of fds, you may not be able to load // the exception class, and get a NoClassDefFoundError instead. @@ -503,7 +503,7 @@ // Let's try to create a RAW socket to send ICMP packets. // This usually requires "root" privileges, so it's likely to fail. - fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); + fd = NET_Socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); if (fd == -1) { return tcp_ping4(env, &sa, netif, timeout, ttl); } else { diff --git a/src/java.base/unix/native/libnet/Inet6AddressImpl.c b/src/java.base/unix/native/libnet/Inet6AddressImpl.c --- a/src/java.base/unix/native/libnet/Inet6AddressImpl.c +++ b/src/java.base/unix/native/libnet/Inet6AddressImpl.c @@ -461,7 +461,7 @@ int connect_rv = -1; // open a TCP socket - fd = socket(AF_INET6, SOCK_STREAM, 0); + fd = NET_Socket(AF_INET6, SOCK_STREAM, 0); if (fd == -1) { // note: if you run out of fds, you may not be able to load // the exception class, and get a NoClassDefFoundError instead. @@ -711,7 +711,7 @@ // Let's try to create a RAW socket to send ICMP packets. // This usually requires "root" privileges, so it's likely to fail. - fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); + fd = NET_Socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); if (fd == -1) { return tcp_ping6(env, &sa, netif, timeout, ttl); } else { diff --git a/src/java.base/unix/native/libnet/NetworkInterface.c b/src/java.base/unix/native/libnet/NetworkInterface.c --- a/src/java.base/unix/native/libnet/NetworkInterface.c +++ b/src/java.base/unix/native/libnet/NetworkInterface.c @@ -1055,7 +1055,7 @@ static int openSocket(JNIEnv *env, int proto) { int sock; - if ((sock = socket(proto, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(proto, SOCK_DGRAM, 0)) < 0) { // If EPROTONOSUPPORT is returned it means we don't have // support for this proto so don't throw an exception. if (errno != EPROTONOSUPPORT) { @@ -1078,9 +1078,9 @@ static int openSocketWithFallback(JNIEnv *env, const char *ifname) { int sock; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) { if (errno == EPROTONOSUPPORT) { - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; @@ -1315,9 +1315,9 @@ static int openSocketWithFallback(JNIEnv *env, const char *ifname) { int sock; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) { if (errno == EPROTONOSUPPORT) { - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; @@ -1590,9 +1590,9 @@ int sock, alreadyV6 = 0; struct lifreq if2; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) { if (errno == EPROTONOSUPPORT) { - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; @@ -1616,7 +1616,7 @@ strncpy(if2.lifr_name, ifname, sizeof(if2.lifr_name) - 1); if (ioctl(sock, SIOCGLIFNETMASK, (char *)&if2) < 0) { close(sock); - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; @@ -1941,9 +1941,9 @@ static int openSocketWithFallback(JNIEnv *env, const char *ifname) { int sock; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) { if (errno == EPROTONOSUPPORT) { - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; diff --git a/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c b/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c --- a/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c +++ b/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c @@ -904,7 +904,7 @@ return; } - if ((fd = socket(domain, SOCK_DGRAM, 0)) == -1) { + if ((fd = NET_Socket(domain, SOCK_DGRAM, 0)) == -1) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "Error creating socket"); return; diff --git a/src/java.base/unix/native/libnet/PlainSocketImpl.c b/src/java.base/unix/native/libnet/PlainSocketImpl.c --- a/src/java.base/unix/native/libnet/PlainSocketImpl.c +++ b/src/java.base/unix/native/libnet/PlainSocketImpl.c @@ -77,7 +77,7 @@ int sv[2]; #ifdef AF_UNIX - if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == -1) { + if (NET_SocketPair(AF_UNIX, SOCK_STREAM, 0, sv) == -1) { return -1; } #else @@ -178,7 +178,7 @@ return; } - if ((fd = socket(domain, type, 0)) == -1) { + if ((fd = NET_Socket(domain, type, 0)) == -1) { /* note: if you run out of fds, you may not be able to load * the exception class, and get a NoClassDefFoundError * instead. diff --git a/src/java.base/unix/native/libnet/SdpSupport.c b/src/java.base/unix/native/libnet/SdpSupport.c --- a/src/java.base/unix/native/libnet/SdpSupport.c +++ b/src/java.base/unix/native/libnet/SdpSupport.c @@ -57,7 +57,7 @@ #if defined(__solaris__) int domain = ipv6_available() ? AF_INET6 : AF_INET; - s = socket(domain, SOCK_STREAM, PROTO_SDP); + s = NET_Socket(domain, SOCK_STREAM, PROTO_SDP); #elif defined(__linux__) /** * IPv6 not supported by SDP on Linux @@ -66,7 +66,7 @@ JNU_ThrowIOException(env, "IPv6 not supported"); return -1; } - s = socket(AF_INET_SDP, SOCK_STREAM, 0); + s = NET_Socket(AF_INET_SDP, SOCK_STREAM, 0); #else /* not supported on other platforms at this time */ s = -1; diff --git a/src/java.base/unix/native/libnet/net_util_md.c b/src/java.base/unix/native/libnet/net_util_md.c --- a/src/java.base/unix/native/libnet/net_util_md.c +++ b/src/java.base/unix/native/libnet/net_util_md.c @@ -117,6 +117,64 @@ return defaultIndex; } +/* + * Opens a socket + * On systems where supported, uses SOCK_CLOEXEC where possible + */ +JNIEXPORT int JNICALL +NET_Socket(int domain, int type, int protocol) { +#if defined(SOCK_CLOEXEC) + int typeToUse = type | SOCK_CLOEXEC; +#else + int typeToUse = type; +#endif + + int socketFileDescriptor = socket(domain, typeToUse, protocol); +#if defined(SOCK_CLOEXEC) + if ((socketFileDescriptor == -1) && (errno = EINVAL)) { + // Attempt to open the socket without SOCK_CLOEXEC + // May have been compiled on an OS with SOCK_CLOEXEC supported + // But runtime system might not have SOCK_CLOEXEC support + socketFileDescriptor = socket(domain, type, protocol); + } +#else + if (socketFileDescriptor != -1) { + // Best effort + // Return value is intentionally ignored since socket was successfully opened anyways + fcntl(socketFileDescriptor, F_SETFD, FD_CLOEXEC); + } +#endif + + return socketFileDescriptor; +} + +JNIEXPORT int JNICALL +NET_SocketPair(int domain, int type, int protocol, int socket_vector[2]) { +#if defined(SOCK_CLOEXEC) + int typeToUse = type | SOCK_CLOEXEC; +#else + int typeToUse = type; +#endif + + int socketFileDescriptor = socketpair(domain, typeToUse, protocol, socket_vector); +#if defined(SOCK_CLOEXEC) + if ((socketFileDescriptor == -1) && (errno = EINVAL)) { + // Attempt to open the socket without SOCK_CLOEXEC + // May have been compiled on an OS with SOCK_CLOEXEC supported + // But runtime system might not have SOCK_CLOEXEC support + socketFileDescriptor = socketpair(domain, type, protocol, socket_vector); + } +#else + if (socketFileDescriptor != -1) { + // Best effort + // Return value is intentionally ignored since socket was successfully opened anyways + fcntl(socketFileDescriptor, F_SETFD, FD_CLOEXEC); + } +#endif + + return socketFileDescriptor; +} + #define RESTARTABLE(_cmd, _result) do { \ do { \ _result = _cmd; \ @@ -295,7 +353,7 @@ SOCKETADDRESS sa; socklen_t sa_len = sizeof(SOCKETADDRESS); - fd = socket(AF_INET6, SOCK_STREAM, 0) ; + fd = NET_Socket(AF_INET6, SOCK_STREAM, 0) ; if (fd < 0) { /* * TODO: We really cant tell since it may be an unrelated error @@ -402,7 +460,7 @@ /* Do a simple dummy call, and try to figure out from that */ int one = 1; int rv, s; - s = socket(PF_INET, SOCK_STREAM, 0); + s = NET_Socket(PF_INET, SOCK_STREAM, 0); if (s < 0) { return JNI_FALSE; } diff --git a/src/java.base/unix/native/libnet/net_util_md.h b/src/java.base/unix/native/libnet/net_util_md.h --- a/src/java.base/unix/native/libnet/net_util_md.h +++ b/src/java.base/unix/native/libnet/net_util_md.h @@ -89,6 +89,8 @@ int NET_Writev(int s, const struct iovec * vector, int count); int NET_Connect(int s, struct sockaddr *addr, int addrlen); int NET_Accept(int s, struct sockaddr *addr, socklen_t *addrlen); +JNIEXPORT int JNICALL NET_Socket(int domain, int type, int protocol); +JNIEXPORT int JNICALL NET_SocketPair(int domain, int type, int protocol, int socket_vector[2]); int NET_SocketClose(int s); int NET_Dup2(int oldfd, int newfd); int NET_Poll(struct pollfd *ufds, unsigned int nfds, int timeout); diff --git a/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c b/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c --- a/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c +++ b/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c @@ -67,7 +67,7 @@ Java_sun_nio_ch_FileDispatcherImpl_init(JNIEnv *env, jclass cl) { int sp[2]; - if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) { + if (NET_SocketPair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) { JNU_ThrowIOExceptionWithLastError(env, "socketpair failed"); return; } diff --git a/src/java.base/unix/native/libnio/ch/Net.c b/src/java.base/unix/native/libnio/ch/Net.c --- a/src/java.base/unix/native/libnio/ch/Net.c +++ b/src/java.base/unix/native/libnio/ch/Net.c @@ -198,7 +198,7 @@ int type = (stream ? SOCK_STREAM : SOCK_DGRAM); int domain = (ipv6_available() && preferIPv6) ? AF_INET6 : AF_INET; - fd = socket(domain, type, 0); + fd = NET_Socket(domain, type, 0); if (fd < 0) { return handleSocketError(env, errno); } diff --git a/src/jdk.net/linux/native/libextnet/LinuxSocketOptions.c b/src/jdk.net/linux/native/libextnet/LinuxSocketOptions.c --- a/src/jdk.net/linux/native/libextnet/LinuxSocketOptions.c +++ b/src/jdk.net/linux/native/libextnet/LinuxSocketOptions.c @@ -86,7 +86,7 @@ (JNIEnv *env, jobject unused) { int one = 1; int rv, s; - s = socket(PF_INET, SOCK_STREAM, 0); + s = NET_Socket(PF_INET, SOCK_STREAM, 0); if (s < 0) { return JNI_FALSE; } @@ -103,7 +103,7 @@ static jint socketOptionSupported(jint sockopt) { jint one = 1; jint rv, s; - s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + s = NET_Socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (s < 0) { return 0; } diff --git a/src/jdk.net/macosx/native/libextnet/MacOSXSocketOptions.c b/src/jdk.net/macosx/native/libextnet/MacOSXSocketOptions.c --- a/src/jdk.net/macosx/native/libextnet/MacOSXSocketOptions.c +++ b/src/jdk.net/macosx/native/libextnet/MacOSXSocketOptions.c @@ -35,7 +35,7 @@ static jint socketOptionSupported(jint sockopt) { jint one = 1; jint rv, s; - s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + s = NET_Socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (s < 0) { return 0; } diff --git a/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.c b/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.c --- a/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.c +++ b/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.c @@ -157,7 +157,7 @@ sock_flow_props_t props; int rv, s; - s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + s = NET_Socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (s < 0) { return JNI_FALSE; } diff --git a/src/jdk.sctp/unix/native/libsctp/SctpNet.c b/src/jdk.sctp/unix/native/libsctp/SctpNet.c --- a/src/jdk.sctp/unix/native/libsctp/SctpNet.c +++ b/src/jdk.sctp/unix/native/libsctp/SctpNet.c @@ -151,7 +151,7 @@ Java_sun_nio_ch_sctp_SctpNet_init (JNIEnv *env, jclass cl) { int sp[2]; - if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) { + if (NET_SocketPair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) { JNU_ThrowIOExceptionWithLastError(env, "socketpair failed"); return; } @@ -180,7 +180,7 @@ return 0; } - fd = socket(domain, (oneToOne ? SOCK_STREAM : SOCK_SEQPACKET), IPPROTO_SCTP); + fd = NET_Socket(domain, (oneToOne ? SOCK_STREAM : SOCK_SEQPACKET), IPPROTO_SCTP); if (fd < 0) { return handleSocketError(env, errno); Thanks, -Andrew -----Original Message----- From: Alan Bateman Sent: Monday, July 16, 2018 11:41 PM To: Andrew Luo Cc: net-dev at openjdk.java.net Subject: Re: [PATCH] SOCK_CLOEXEC for opening sockets On 17/07/2018 07:33, Andrew Luo wrote: > Great, thanks. > > By the way, I do see other places where we use NET_* functions in > libnio, but if you prefer that I duplicate that code instead, It's okay for the code in libnio/ch to use the NET_* functions. The issue is the changes to libnio/fs which is the file system code as that should have no dependences on functions exported by libnet. I think it would be better to drop the changes to the fs code in this patch. As we've been discussing, there are dozens of other areas that will work to allow fork/exec work reliably in native code, I think the networking and channels area is just the first step. -Alan From andrewluotechnologies at outlook.com Thu Jul 19 17:41:28 2018 From: andrewluotechnologies at outlook.com (Andrew Luo) Date: Thu, 19 Jul 2018 17:41:28 +0000 Subject: [PATCH] SOCK_CLOEXEC for opening sockets In-Reply-To: References: <0c24795d-350e-3ac8-4417-0480b41c5c9c@oracle.com> <83f34e37-5cb6-832d-2858-26377d1c8e9d@oracle.com> <3f50f583-a990-fb70-da1d-df2c7b26e08e@oracle.com> <6d445479-e05e-1dcc-fe25-81ee17acb219@oracle.com> Message-ID: Just checking - is there any other changes that I should make to the patch, or anything else you guys need me to do? Thanks, -Andrew -----Original Message----- From: net-dev On Behalf Of Andrew Luo Sent: Monday, July 16, 2018 11:59 PM To: Alan Bateman Cc: net-dev at openjdk.java.net Subject: RE: [PATCH] SOCK_CLOEXEC for opening sockets Thanks for the feedback. Made those changes (reverted src/java.base/linux/native/libnio/fs/LinuxWatchService.c): diff --git a/make/lib/Lib-jdk.net.gmk b/make/lib/Lib-jdk.net.gmk --- a/make/lib/Lib-jdk.net.gmk +++ b/make/lib/Lib-jdk.net.gmk @@ -35,7 +35,7 @@ CFLAGS := $(CFLAGS_JDKLIB), \ LDFLAGS := $(LDFLAGS_JDKLIB) \ $(call SET_SHARED_LIBRARY_ORIGIN), \ - LIBS := -ljava, \ + LIBS := -ljava -lnet, \ LIBS_solaris := -lsocket, \ LIBS_linux := -ljvm, \ )) diff --git a/src/java.base/aix/native/libnio/ch/AixPollPort.c b/src/java.base/aix/native/libnio/ch/AixPollPort.c --- a/src/java.base/aix/native/libnio/ch/AixPollPort.c +++ b/src/java.base/aix/native/libnio/ch/AixPollPort.c @@ -137,7 +137,7 @@ JNIEXPORT void JNICALL Java_sun_nio_ch_AixPollPort_socketpair(JNIEnv* env, jclass clazz, jintArray sv) { int sp[2]; - if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) == -1) { + if (NET_SocketPair(PF_UNIX, SOCK_STREAM, 0, sp) == -1) { JNU_ThrowIOExceptionWithLastError(env, "socketpair failed"); } else { jint res[2]; diff --git a/src/java.base/unix/native/libnet/Inet4AddressImpl.c b/src/java.base/unix/native/libnet/Inet4AddressImpl.c --- a/src/java.base/unix/native/libnet/Inet4AddressImpl.c +++ b/src/java.base/unix/native/libnet/Inet4AddressImpl.c @@ -264,7 +264,7 @@ int connect_rv = -1; // open a TCP socket - fd = socket(AF_INET, SOCK_STREAM, 0); + fd = NET_Socket(AF_INET, SOCK_STREAM, 0); if (fd == -1) { // note: if you run out of fds, you may not be able to load // the exception class, and get a NoClassDefFoundError instead. @@ -503,7 +503,7 @@ // Let's try to create a RAW socket to send ICMP packets. // This usually requires "root" privileges, so it's likely to fail. - fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); + fd = NET_Socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); if (fd == -1) { return tcp_ping4(env, &sa, netif, timeout, ttl); } else { diff --git a/src/java.base/unix/native/libnet/Inet6AddressImpl.c b/src/java.base/unix/native/libnet/Inet6AddressImpl.c --- a/src/java.base/unix/native/libnet/Inet6AddressImpl.c +++ b/src/java.base/unix/native/libnet/Inet6AddressImpl.c @@ -461,7 +461,7 @@ int connect_rv = -1; // open a TCP socket - fd = socket(AF_INET6, SOCK_STREAM, 0); + fd = NET_Socket(AF_INET6, SOCK_STREAM, 0); if (fd == -1) { // note: if you run out of fds, you may not be able to load // the exception class, and get a NoClassDefFoundError instead. @@ -711,7 +711,7 @@ // Let's try to create a RAW socket to send ICMP packets. // This usually requires "root" privileges, so it's likely to fail. - fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); + fd = NET_Socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); if (fd == -1) { return tcp_ping6(env, &sa, netif, timeout, ttl); } else { diff --git a/src/java.base/unix/native/libnet/NetworkInterface.c b/src/java.base/unix/native/libnet/NetworkInterface.c --- a/src/java.base/unix/native/libnet/NetworkInterface.c +++ b/src/java.base/unix/native/libnet/NetworkInterface.c @@ -1055,7 +1055,7 @@ static int openSocket(JNIEnv *env, int proto) { int sock; - if ((sock = socket(proto, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(proto, SOCK_DGRAM, 0)) < 0) { // If EPROTONOSUPPORT is returned it means we don't have // support for this proto so don't throw an exception. if (errno != EPROTONOSUPPORT) { @@ -1078,9 +1078,9 @@ static int openSocketWithFallback(JNIEnv *env, const char *ifname) { int sock; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) { if (errno == EPROTONOSUPPORT) { - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; @@ -1315,9 +1315,9 @@ static int openSocketWithFallback(JNIEnv *env, const char *ifname) { int sock; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) { if (errno == EPROTONOSUPPORT) { - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; @@ -1590,9 +1590,9 @@ int sock, alreadyV6 = 0; struct lifreq if2; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) { if (errno == EPROTONOSUPPORT) { - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; @@ -1616,7 +1616,7 @@ strncpy(if2.lifr_name, ifname, sizeof(if2.lifr_name) - 1); if (ioctl(sock, SIOCGLIFNETMASK, (char *)&if2) < 0) { close(sock); - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; @@ -1941,9 +1941,9 @@ static int openSocketWithFallback(JNIEnv *env, const char *ifname) { int sock; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) { if (errno == EPROTONOSUPPORT) { - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; diff --git a/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c b/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c --- a/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c +++ b/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c @@ -904,7 +904,7 @@ return; } - if ((fd = socket(domain, SOCK_DGRAM, 0)) == -1) { + if ((fd = NET_Socket(domain, SOCK_DGRAM, 0)) == -1) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "Error creating socket"); return; diff --git a/src/java.base/unix/native/libnet/PlainSocketImpl.c b/src/java.base/unix/native/libnet/PlainSocketImpl.c --- a/src/java.base/unix/native/libnet/PlainSocketImpl.c +++ b/src/java.base/unix/native/libnet/PlainSocketImpl.c @@ -77,7 +77,7 @@ int sv[2]; #ifdef AF_UNIX - if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == -1) { + if (NET_SocketPair(AF_UNIX, SOCK_STREAM, 0, sv) == -1) { return -1; } #else @@ -178,7 +178,7 @@ return; } - if ((fd = socket(domain, type, 0)) == -1) { + if ((fd = NET_Socket(domain, type, 0)) == -1) { /* note: if you run out of fds, you may not be able to load * the exception class, and get a NoClassDefFoundError * instead. diff --git a/src/java.base/unix/native/libnet/SdpSupport.c b/src/java.base/unix/native/libnet/SdpSupport.c --- a/src/java.base/unix/native/libnet/SdpSupport.c +++ b/src/java.base/unix/native/libnet/SdpSupport.c @@ -57,7 +57,7 @@ #if defined(__solaris__) int domain = ipv6_available() ? AF_INET6 : AF_INET; - s = socket(domain, SOCK_STREAM, PROTO_SDP); + s = NET_Socket(domain, SOCK_STREAM, PROTO_SDP); #elif defined(__linux__) /** * IPv6 not supported by SDP on Linux @@ -66,7 +66,7 @@ JNU_ThrowIOException(env, "IPv6 not supported"); return -1; } - s = socket(AF_INET_SDP, SOCK_STREAM, 0); + s = NET_Socket(AF_INET_SDP, SOCK_STREAM, 0); #else /* not supported on other platforms at this time */ s = -1; diff --git a/src/java.base/unix/native/libnet/net_util_md.c b/src/java.base/unix/native/libnet/net_util_md.c --- a/src/java.base/unix/native/libnet/net_util_md.c +++ b/src/java.base/unix/native/libnet/net_util_md.c @@ -117,6 +117,64 @@ return defaultIndex; } +/* + * Opens a socket + * On systems where supported, uses SOCK_CLOEXEC where possible */ +JNIEXPORT int JNICALL NET_Socket(int domain, int type, int protocol) { +#if defined(SOCK_CLOEXEC) + int typeToUse = type | SOCK_CLOEXEC; #else + int typeToUse = type; +#endif + + int socketFileDescriptor = socket(domain, typeToUse, protocol); #if +defined(SOCK_CLOEXEC) + if ((socketFileDescriptor == -1) && (errno = EINVAL)) { + // Attempt to open the socket without SOCK_CLOEXEC + // May have been compiled on an OS with SOCK_CLOEXEC supported + // But runtime system might not have SOCK_CLOEXEC support + socketFileDescriptor = socket(domain, type, protocol); + } +#else + if (socketFileDescriptor != -1) { + // Best effort + // Return value is intentionally ignored since socket was successfully opened anyways + fcntl(socketFileDescriptor, F_SETFD, FD_CLOEXEC); + } +#endif + + return socketFileDescriptor; +} + +JNIEXPORT int JNICALL +NET_SocketPair(int domain, int type, int protocol, int +socket_vector[2]) { #if defined(SOCK_CLOEXEC) + int typeToUse = type | SOCK_CLOEXEC; #else + int typeToUse = type; +#endif + + int socketFileDescriptor = socketpair(domain, typeToUse, protocol, +socket_vector); #if defined(SOCK_CLOEXEC) + if ((socketFileDescriptor == -1) && (errno = EINVAL)) { + // Attempt to open the socket without SOCK_CLOEXEC + // May have been compiled on an OS with SOCK_CLOEXEC supported + // But runtime system might not have SOCK_CLOEXEC support + socketFileDescriptor = socketpair(domain, type, protocol, socket_vector); + } +#else + if (socketFileDescriptor != -1) { + // Best effort + // Return value is intentionally ignored since socket was successfully opened anyways + fcntl(socketFileDescriptor, F_SETFD, FD_CLOEXEC); + } +#endif + + return socketFileDescriptor; +} + #define RESTARTABLE(_cmd, _result) do { \ do { \ _result = _cmd; \ @@ -295,7 +353,7 @@ SOCKETADDRESS sa; socklen_t sa_len = sizeof(SOCKETADDRESS); - fd = socket(AF_INET6, SOCK_STREAM, 0) ; + fd = NET_Socket(AF_INET6, SOCK_STREAM, 0) ; if (fd < 0) { /* * TODO: We really cant tell since it may be an unrelated error @@ -402,7 +460,7 @@ /* Do a simple dummy call, and try to figure out from that */ int one = 1; int rv, s; - s = socket(PF_INET, SOCK_STREAM, 0); + s = NET_Socket(PF_INET, SOCK_STREAM, 0); if (s < 0) { return JNI_FALSE; } diff --git a/src/java.base/unix/native/libnet/net_util_md.h b/src/java.base/unix/native/libnet/net_util_md.h --- a/src/java.base/unix/native/libnet/net_util_md.h +++ b/src/java.base/unix/native/libnet/net_util_md.h @@ -89,6 +89,8 @@ int NET_Writev(int s, const struct iovec * vector, int count); int NET_Connect(int s, struct sockaddr *addr, int addrlen); int NET_Accept(int s, struct sockaddr *addr, socklen_t *addrlen); +JNIEXPORT int JNICALL NET_Socket(int domain, int type, int protocol); +JNIEXPORT int JNICALL NET_SocketPair(int domain, int type, int +protocol, int socket_vector[2]); int NET_SocketClose(int s); int NET_Dup2(int oldfd, int newfd); int NET_Poll(struct pollfd *ufds, unsigned int nfds, int timeout); diff --git a/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c b/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c --- a/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c +++ b/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c @@ -67,7 +67,7 @@ Java_sun_nio_ch_FileDispatcherImpl_init(JNIEnv *env, jclass cl) { int sp[2]; - if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) { + if (NET_SocketPair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) { JNU_ThrowIOExceptionWithLastError(env, "socketpair failed"); return; } diff --git a/src/java.base/unix/native/libnio/ch/Net.c b/src/java.base/unix/native/libnio/ch/Net.c --- a/src/java.base/unix/native/libnio/ch/Net.c +++ b/src/java.base/unix/native/libnio/ch/Net.c @@ -198,7 +198,7 @@ int type = (stream ? SOCK_STREAM : SOCK_DGRAM); int domain = (ipv6_available() && preferIPv6) ? AF_INET6 : AF_INET; - fd = socket(domain, type, 0); + fd = NET_Socket(domain, type, 0); if (fd < 0) { return handleSocketError(env, errno); } diff --git a/src/jdk.net/linux/native/libextnet/LinuxSocketOptions.c b/src/jdk.net/linux/native/libextnet/LinuxSocketOptions.c --- a/src/jdk.net/linux/native/libextnet/LinuxSocketOptions.c +++ b/src/jdk.net/linux/native/libextnet/LinuxSocketOptions.c @@ -86,7 +86,7 @@ (JNIEnv *env, jobject unused) { int one = 1; int rv, s; - s = socket(PF_INET, SOCK_STREAM, 0); + s = NET_Socket(PF_INET, SOCK_STREAM, 0); if (s < 0) { return JNI_FALSE; } @@ -103,7 +103,7 @@ static jint socketOptionSupported(jint sockopt) { jint one = 1; jint rv, s; - s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + s = NET_Socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (s < 0) { return 0; } diff --git a/src/jdk.net/macosx/native/libextnet/MacOSXSocketOptions.c b/src/jdk.net/macosx/native/libextnet/MacOSXSocketOptions.c --- a/src/jdk.net/macosx/native/libextnet/MacOSXSocketOptions.c +++ b/src/jdk.net/macosx/native/libextnet/MacOSXSocketOptions.c @@ -35,7 +35,7 @@ static jint socketOptionSupported(jint sockopt) { jint one = 1; jint rv, s; - s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + s = NET_Socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (s < 0) { return 0; } diff --git a/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.c b/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.c --- a/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.c +++ b/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.c @@ -157,7 +157,7 @@ sock_flow_props_t props; int rv, s; - s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + s = NET_Socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (s < 0) { return JNI_FALSE; } diff --git a/src/jdk.sctp/unix/native/libsctp/SctpNet.c b/src/jdk.sctp/unix/native/libsctp/SctpNet.c --- a/src/jdk.sctp/unix/native/libsctp/SctpNet.c +++ b/src/jdk.sctp/unix/native/libsctp/SctpNet.c @@ -151,7 +151,7 @@ Java_sun_nio_ch_sctp_SctpNet_init (JNIEnv *env, jclass cl) { int sp[2]; - if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) { + if (NET_SocketPair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) { JNU_ThrowIOExceptionWithLastError(env, "socketpair failed"); return; } @@ -180,7 +180,7 @@ return 0; } - fd = socket(domain, (oneToOne ? SOCK_STREAM : SOCK_SEQPACKET), IPPROTO_SCTP); + fd = NET_Socket(domain, (oneToOne ? SOCK_STREAM : SOCK_SEQPACKET), + IPPROTO_SCTP); if (fd < 0) { return handleSocketError(env, errno); Thanks, -Andrew -----Original Message----- From: Alan Bateman Sent: Monday, July 16, 2018 11:41 PM To: Andrew Luo Cc: net-dev at openjdk.java.net Subject: Re: [PATCH] SOCK_CLOEXEC for opening sockets On 17/07/2018 07:33, Andrew Luo wrote: > Great, thanks. > > By the way, I do see other places where we use NET_* functions in > libnio, but if you prefer that I duplicate that code instead, It's okay for the code in libnio/ch to use the NET_* functions. The issue is the changes to libnio/fs which is the file system code as that should have no dependences on functions exported by libnet. I think it would be better to drop the changes to the fs code in this patch. As we've been discussing, there are dozens of other areas that will work to allow fork/exec work reliably in native code, I think the networking and channels area is just the first step. -Alan From sgehwolf at redhat.com Fri Jul 20 07:38:26 2018 From: sgehwolf at redhat.com (Severin Gehwolf) Date: Fri, 20 Jul 2018 09:38:26 +0200 Subject: Bug in HttpClient In-Reply-To: References: Message-ID: <27900b892ab06fad766652b87445450747bc1a8c.camel@redhat.com> Adding net-dev On Fri, 2018-07-20 at 08:52 +0200, Thomas Lu?nig wrote: > Hi, > i found an bug in JDK 10 with the new HttpClient. It does not handle > responses wihtout contentlength correctly. > Normally i would expect that the content is returned even without > content length. Since i can not open an JDK bug > i hope some person from the list can do it. Below is an example that > show the problem. > > Gru? Thomas Lu?nig > import java.io.InputStream; > import java.io.OutputStream; > import java.net.InetSocketAddress; > import java.net.ServerSocket; > import java.net.Socket; > import java.net.URI; > import java.time.Duration; > import javax.net.ServerSocketFactory; > import jdk.incubator.http.HttpClient; > import jdk.incubator.http.HttpRequest; > import jdk.incubator.http.HttpResponse; > public class Client1 { > static void server(final boolean withContentLength) { > try(ServerSocket ss = > ServerSocketFactory.getDefault().createServerSocket()) { > ss.setReuseAddress(true); > ss.bind(new InetSocketAddress("127.0.0.1",80)); > final byte[] buf = new byte[120400]; > try(Socket s = ss.accept()) { > System.out.println("Accepted: > "+s.getRemoteSocketAddress()); > try( OutputStream os = > s.getOutputStream(); InputStream is = s.getInputStream()) { > is.read(buf); > is.read(buf); > os.write("HTTP/1.0 200 > OK\r\nConnection: close\r\nContent-Type: text/xml; charset=UTF- > 8\r\n".getBytes()); > if(withContentLength) > os.write("Content-Length: 4\r\n".getBytes()); > os.write("\r\n".getBytes()); > os.write("".getBytes()); > os.flush(); > } > } > } catch(final Throwable t) { t.printStackTrace(); } > } > static void client() { > try { > final HttpClient client = > HttpClient.newBuilder().version(HttpClient.Version.HTTP_2).build(); > final HttpResponse response = client > .send(HttpRequest.newBuilder(new URI("htt > p://127.0.0.1/test")).timeout(Duration.ofMillis(120_000)) > > .POST(HttpRequest.BodyPublisher.fromString("body")).build(), > HttpResponse.BodyHandler.asString()); > System.out.println("Received reply: " + > response.statusCode()); > System.out.println("Received body: " + > response.body()); > } catch(final Throwable t) { t.printStackTrace(); } > } > public static void main(final String[] args) throws Exception > { > new Thread(()->server(true)).start(); > client(); > new Thread(()->server(false)).start(); > client(); > } > } From felix.yang at oracle.com Fri Jul 20 09:27:38 2018 From: felix.yang at oracle.com (Felix Yang) Date: Fri, 20 Jul 2018 17:27:38 +0800 Subject: RFR 8207952/11, Problem-list 3 sctp tests Message-ID: Hi all, ??? please review the following patch to problem-list 3 sctp tests, which have been observed to be quite unstable on OEL 7 x64. Bug: ???? https://bugs.openjdk.java.net/browse/JDK-8207952 Problem-listing cause: ???? https://bugs.openjdk.java.net/browse/JDK-8141694 Patch: diff -r 6c62929bd870 test/jdk/ProblemList.txt --- a/test/jdk/ProblemList.txt? Thu Jul 19 16:53:33 2018 -0700 +++ b/test/jdk/ProblemList.txt? Fri Jul 20 01:54:46 2018 -0700 @@ -595,6 +595,16 @@ ?############################################################################ +# jdk_sctp + +com/sun/nio/sctp/SctpMultiChannel/SendFailed.java 8141694 linux-all + +com/sun/nio/sctp/SctpMultiChannel/SocketOptionTests.java 8141694 linux-all + +com/sun/nio/sctp/SctpChannel/SocketOptionTests.java 8141694 linux-all + +############################################################################ + ?# jdk_security ?sun/security/pkcs11/ec/TestKeyFactory.java 8026976 generic-all Thanks, Felix From chris.hegarty at oracle.com Fri Jul 20 09:48:19 2018 From: chris.hegarty at oracle.com (Chris Hegarty) Date: Fri, 20 Jul 2018 10:48:19 +0100 Subject: RFR 8207952/11, Problem-list 3 sctp tests In-Reply-To: References: Message-ID: Looks ok Felix. -Chris > On 20 Jul 2018, at 10:27, Felix Yang wrote: > > Hi all, > > please review the following patch to problem-list 3 sctp tests, which have been observed to be quite unstable on OEL 7 x64. > > Bug: > > https://bugs.openjdk.java.net/browse/JDK-8207952 > > Problem-listing cause: > > https://bugs.openjdk.java.net/browse/JDK-8141694 > > Patch: > > diff -r 6c62929bd870 test/jdk/ProblemList.txt > --- a/test/jdk/ProblemList.txt Thu Jul 19 16:53:33 2018 -0700 > +++ b/test/jdk/ProblemList.txt Fri Jul 20 01:54:46 2018 -0700 > @@ -595,6 +595,16 @@ > > ############################################################################ > > +# jdk_sctp > + > +com/sun/nio/sctp/SctpMultiChannel/SendFailed.java 8141694 linux-all > + > +com/sun/nio/sctp/SctpMultiChannel/SocketOptionTests.java 8141694 linux-all > + > +com/sun/nio/sctp/SctpChannel/SocketOptionTests.java 8141694 linux-all > + > +############################################################################ > + > # jdk_security > > sun/security/pkcs11/ec/TestKeyFactory.java 8026976 generic-all > > > Thanks, > > Felix > From michael.x.mcmahon at oracle.com Fri Jul 20 10:35:54 2018 From: michael.x.mcmahon at oracle.com (Michael McMahon) Date: Fri, 20 Jul 2018 11:35:54 +0100 Subject: Bug in HttpClient In-Reply-To: <27900b892ab06fad766652b87445450747bc1a8c.camel@redhat.com> References: <27900b892ab06fad766652b87445450747bc1a8c.camel@redhat.com> Message-ID: <5B51BB0A.3090205@oracle.com> Thanks for reporting this. I will look into it. - Michael On 20/07/2018, 08:38, Severin Gehwolf wrote: > Adding net-dev > > On Fri, 2018-07-20 at 08:52 +0200, Thomas Lu?nig wrote: >> Hi, >> i found an bug in JDK 10 with the new HttpClient. It does not handle >> responses wihtout contentlength correctly. >> Normally i would expect that the content is returned even without >> content length. Since i can not open an JDK bug >> i hope some person from the list can do it. Below is an example that >> show the problem. >> >> Gru? Thomas Lu?nig >> import java.io.InputStream; >> import java.io.OutputStream; >> import java.net.InetSocketAddress; >> import java.net.ServerSocket; >> import java.net.Socket; >> import java.net.URI; >> import java.time.Duration; >> import javax.net.ServerSocketFactory; >> import jdk.incubator.http.HttpClient; >> import jdk.incubator.http.HttpRequest; >> import jdk.incubator.http.HttpResponse; >> public class Client1 { >> static void server(final boolean withContentLength) { >> try(ServerSocket ss = >> ServerSocketFactory.getDefault().createServerSocket()) { >> ss.setReuseAddress(true); >> ss.bind(new InetSocketAddress("127.0.0.1",80)); >> final byte[] buf = new byte[120400]; >> try(Socket s = ss.accept()) { >> System.out.println("Accepted: >> "+s.getRemoteSocketAddress()); >> try( OutputStream os = >> s.getOutputStream(); InputStream is = s.getInputStream()) { >> is.read(buf); >> is.read(buf); >> os.write("HTTP/1.0 200 >> OK\r\nConnection: close\r\nContent-Type: text/xml; charset=UTF- >> 8\r\n".getBytes()); >> if(withContentLength) >> os.write("Content-Length: 4\r\n".getBytes()); >> os.write("\r\n".getBytes()); >> os.write("".getBytes()); >> os.flush(); >> } >> } >> } catch(final Throwable t) { t.printStackTrace(); } >> } >> static void client() { >> try { >> final HttpClient client = >> HttpClient.newBuilder().version(HttpClient.Version.HTTP_2).build(); >> final HttpResponse response = client >> .send(HttpRequest.newBuilder(new URI("htt >> p://127.0.0.1/test")).timeout(Duration.ofMillis(120_000)) >> >> .POST(HttpRequest.BodyPublisher.fromString("body")).build(), >> HttpResponse.BodyHandler.asString()); >> System.out.println("Received reply: " + >> response.statusCode()); >> System.out.println("Received body: " + >> response.body()); >> } catch(final Throwable t) { t.printStackTrace(); } >> } >> public static void main(final String[] args) throws Exception >> { >> new Thread(()->server(true)).start(); >> client(); >> new Thread(()->server(false)).start(); >> client(); >> } >> } From chris.hegarty at oracle.com Mon Jul 23 10:43:50 2018 From: chris.hegarty at oracle.com (Chris Hegarty) Date: Mon, 23 Jul 2018 11:43:50 +0100 Subject: RFR [11 8207959 The initial value of SETTINGS_MAX_CONCURRENT_STREAMS should have no limit Message-ID: <45FDA145-1056-403C-8477-6B1B18CF895C@oracle.com> The initial value for the directional parameter SETTINGS_MAX_CONCURRENT_STREAMS, in the direction from the server to the client, max concurrent client-initiated streams, is incorrectly limited to 100, when there should be no initial limit. Note, the client retains its, configurable, limit of 100 server-initiated streams.. From section 6.5.2. Defined SETTINGS Parameters: SETTINGS_MAX_CONCURRENT_STREAMS (0x3): Indicates the maximum number of concurrent streams that the sender will allow. This limit is directional: it applies to the number of streams that the sender permits the receiver to create. *** Initially, there is no limit to this value***. It is recommended that this value be no smaller than 100, so as to not unnecessarily limit parallelism. ? https://bugs.openjdk.java.net/browse/JDK-8207959 http://cr.openjdk.java.net/~chegar/8207959/webrev.00/ A few methods have been renamed in the webrev, to improve readability. -Chris. From chris.hegarty at oracle.com Mon Jul 23 11:02:30 2018 From: chris.hegarty at oracle.com (Chris Hegarty) Date: Mon, 23 Jul 2018 12:02:30 +0100 Subject: Bug in HttpClient In-Reply-To: <27900b892ab06fad766652b87445450747bc1a8c.camel@redhat.com> References: <27900b892ab06fad766652b87445450747bc1a8c.camel@redhat.com> Message-ID: The following issue has been filed in JIRA to track the problem with an HTTP/1.0 response without a Content-Length header: https://bugs.openjdk.java.net/browse/JDK-8207966 -Chris. > On 20 Jul 2018, at 08:38, Severin Gehwolf wrote: > > Adding net-dev > > On Fri, 2018-07-20 at 08:52 +0200, Thomas Lu?nig wrote: >> Hi, >> i found an bug in JDK 10 with the new HttpClient. It does not handle >> responses wihtout contentlength correctly. >> Normally i would expect that the content is returned even without >> content length. Since i can not open an JDK bug >> i hope some person from the list can do it. Below is an example that >> show the problem. >> >> Gru? Thomas Lu?nig >> import java.io.InputStream; >> import java.io.OutputStream; >> import java.net.InetSocketAddress; >> import java.net.ServerSocket; >> import java.net.Socket; >> import java.net.URI; >> import java.time.Duration; >> import javax.net.ServerSocketFactory; >> import jdk.incubator.http.HttpClient; >> import jdk.incubator.http.HttpRequest; >> import jdk.incubator.http.HttpResponse; >> public class Client1 { >> static void server(final boolean withContentLength) { >> try(ServerSocket ss = >> ServerSocketFactory.getDefault().createServerSocket()) { >> ss.setReuseAddress(true); >> ss.bind(new InetSocketAddress("127.0.0.1",80)); >> final byte[] buf = new byte[120400]; >> try(Socket s = ss.accept()) { >> System.out.println("Accepted: >> "+s.getRemoteSocketAddress()); >> try( OutputStream os = >> s.getOutputStream(); InputStream is = s.getInputStream()) { >> is.read(buf); >> is.read(buf); >> os.write("HTTP/1.0 200 >> OK\r\nConnection: close\r\nContent-Type: text/xml; charset=UTF- >> 8\r\n".getBytes()); >> if(withContentLength) >> os.write("Content-Length: 4\r\n".getBytes()); >> os.write("\r\n".getBytes()); >> os.write("".getBytes()); >> os.flush(); >> } >> } >> } catch(final Throwable t) { t.printStackTrace(); } >> } >> static void client() { >> try { >> final HttpClient client = >> HttpClient.newBuilder().version(HttpClient.Version.HTTP_2).build(); >> final HttpResponse response = client >> .send(HttpRequest.newBuilder(new URI("htt >> p://127.0.0.1/test")).timeout(Duration.ofMillis(120_000)) >> >> .POST(HttpRequest.BodyPublisher.fromString("body")).build(), >> HttpResponse.BodyHandler.asString()); >> System.out.println("Received reply: " + >> response.statusCode()); >> System.out.println("Received body: " + >> response.body()); >> } catch(final Throwable t) { t.printStackTrace(); } >> } >> public static void main(final String[] args) throws Exception >> { >> new Thread(()->server(true)).start(); >> client(); >> new Thread(()->server(false)).start(); >> client(); >> } >> } From michael.x.mcmahon at oracle.com Tue Jul 24 09:11:30 2018 From: michael.x.mcmahon at oracle.com (Michael McMahon) Date: Tue, 24 Jul 2018 10:11:30 +0100 Subject: RFR [11 8207959 The initial value of SETTINGS_MAX_CONCURRENT_STREAMS should have no limit In-Reply-To: <45FDA145-1056-403C-8477-6B1B18CF895C@oracle.com> References: <45FDA145-1056-403C-8477-6B1B18CF895C@oracle.com> Message-ID: <5B56ED42.1010608@oracle.com> This looks fine, Chris. - Michael. On 23/07/2018, 11:43, Chris Hegarty wrote: > The initial value for the directional parameter SETTINGS_MAX_CONCURRENT_STREAMS, > in the direction from the server to the client, max concurrent > client-initiated streams, is incorrectly limited to 100, when there > should be no initial limit. Note, the client retains its, configurable, > limit of 100 server-initiated streams.. > > From section 6.5.2. Defined SETTINGS Parameters: > > SETTINGS_MAX_CONCURRENT_STREAMS (0x3): Indicates the maximum number > of concurrent streams that the sender will allow. This limit is > directional: it applies to the number of streams that the sender > permits the receiver to create. *** Initially, there is no limit to > this value***. It is recommended that this value be no smaller than > 100, so as to not unnecessarily limit parallelism. ? > > > https://bugs.openjdk.java.net/browse/JDK-8207959 > http://cr.openjdk.java.net/~chegar/8207959/webrev.00/ > > A few methods have been renamed in the webrev, to improve > readability. > > -Chris. From chris.hegarty at oracle.com Tue Jul 24 09:23:55 2018 From: chris.hegarty at oracle.com (Chris Hegarty) Date: Tue, 24 Jul 2018 10:23:55 +0100 Subject: RFR [11] 8207960: Non-negative WINDOW_UPDATE increments may leave the stream window size negative Message-ID: The stream window size can correctly become negative after processing the initial SETTINGS_INITIAL_WINDOW_SIZE. Stream specific WINDOW_UPDATE's should not cause a stream reset if the current window size is negative before the positive increment amount is added. http://cr.openjdk.java.net/~chegar/8207960/webrev.00/ https://bugs.openjdk.java.net/browse/JDK-8207960 -Chris. From vyom.tewari at oracle.com Tue Jul 24 09:55:11 2018 From: vyom.tewari at oracle.com (vyom tewari) Date: Tue, 24 Jul 2018 15:25:11 +0530 Subject: RFR: 8172346 sun.net.ftp.FtpDirEntry.setCreated(Date) may expose internal represent Message-ID: Hi All, Please review below a trivial fix. Webrev : http://cr.openjdk.java.net/~vtewari/8172346/webrev0.0/index.html BugID: https://bugs.openjdk.java.net/browse/JDK-8172346 The above code change will avoid storing the externally mutable object reference into FtpDirEntry. Thanks, Vyom From michael.x.mcmahon at oracle.com Tue Jul 24 10:56:10 2018 From: michael.x.mcmahon at oracle.com (Michael McMahon) Date: Tue, 24 Jul 2018 11:56:10 +0100 Subject: RFR [11] 8207960: Non-negative WINDOW_UPDATE increments may leave the stream window size negative In-Reply-To: References: Message-ID: <5B5705CA.2010105@oracle.com> Looks good Chris - Michael. On 24/07/2018, 10:23, Chris Hegarty wrote: > The stream window size can correctly become negative after processing > the initial SETTINGS_INITIAL_WINDOW_SIZE. Stream specific > WINDOW_UPDATE's should not cause a stream reset if the current > window size is negative before the positive increment amount is added. > > http://cr.openjdk.java.net/~chegar/8207960/webrev.00/ > https://bugs.openjdk.java.net/browse/JDK-8207960 > > -Chris. From chris.hegarty at oracle.com Tue Jul 24 13:24:20 2018 From: chris.hegarty at oracle.com (Chris Hegarty) Date: Tue, 24 Jul 2018 14:24:20 +0100 Subject: RFR: 8172346 sun.net.ftp.FtpDirEntry.setCreated(Date) may expose internal represent In-Reply-To: References: Message-ID: On 24 Jul 2018, at 10:55, vyom tewari wrote: > > Hi All, > > Please review below a trivial fix. > > Webrev : http://cr.openjdk.java.net/~vtewari/8172346/webrev0.0/index.html > > BugID: https://bugs.openjdk.java.net/browse/JDK-8172346 > > The above code change will avoid storing the externally mutable object reference into FtpDirEntry. Is this defensive coding really needed here, given that the class is internal and only ever used by the FTP URL protocol handler? If it is not really needed, then maybe we just close the bug as ?not an issue?. -Chris. From vyom.tewari at oracle.com Tue Jul 24 14:21:39 2018 From: vyom.tewari at oracle.com (vyom tewari) Date: Tue, 24 Jul 2018 19:51:39 +0530 Subject: RFR: 8172346 sun.net.ftp.FtpDirEntry.setCreated(Date) may expose internal represent In-Reply-To: References: Message-ID: Hi Chris, Thanks for review, please find my comment inline. Thanks, Vyom On Tuesday 24 July 2018 06:54 PM, Chris Hegarty wrote: > On 24 Jul 2018, at 10:55, vyom tewari wrote: >> Hi All, >> >> Please review below a trivial fix. >> >> Webrev : http://cr.openjdk.java.net/~vtewari/8172346/webrev0.0/index.html >> >> BugID: https://bugs.openjdk.java.net/browse/JDK-8172346 >> >> The above code change will avoid storing the externally mutable object reference into FtpDirEntry. > Is this defensive coding really needed here, given that the > class is internal and only ever used by the FTP URL protocol > handler? It is good to have but i agree with you as class is internal and part of non-exported package so it is not really needed. > If it is not really needed, then maybe we just close the bug as > ?not an issue?. > -Chris. From sean.mullan at oracle.com Tue Jul 24 15:58:18 2018 From: sean.mullan at oracle.com (Sean Mullan) Date: Tue, 24 Jul 2018 11:58:18 -0400 Subject: HttpURLConnection throws SunCertPathBuilderException in jdk11 In-Reply-To: References: <1f4645dd-349a-4958-b358-6511a778f131@oracle.com> Message-ID: <4488846c-74dc-c782-92a4-4508d1984500@oracle.com> This should be fixed in JDK 11 b23. Please try again. See https://bugs.openjdk.java.net/browse/JDK-8199779 for more info. --Sean On 6/25/18 12:28 AM, Jaikiran Pai wrote: > I couldn't locate this bug in the JIRA nor the bugs.java.net, to see if > it's acknowledged as an issue. So FWIW - I can reproduce this even on > MacOS (so it isn't just specific to Windows OS). This is the code: > > import java.net.URL; > import java.io.InputStream; > > public class CertTest { > ??? public static void main(final String[] args) throws Exception { > ??? ??? final URL targetURL = new URL("https://api.vk.com/"); > ??? ??? try (final InputStream is = > targetURL.openConnection().getInputStream()) { > ??? ??? ??? is.read(); > ??? ??? } > ??? } > } > > > -Jaikiran > > > On 16/06/18 12:51 AM, Andrey Turbanov wrote: >> Thank you for response. >> I submitted bug to bugtracker. Iinternal review ID : 9055666 >> Didn't find a way to attach files there, but program example is short >> and can be easily run by anyone. >> >> >> Andrey Turbanov. >> >> 2018-06-15 16:58 GMT+03:00 Sean Mullan > >: >> >> The 2nd (good) logfile looks like it is from a completely >> different program - are you sure you are using the same code? >> >> If it is, please rerun again and also add -Djavax.net.debug=all to >> the command-line which should give a bit more debug info as to >> where the issue is occurring in the TLS handshake. >> >> I would also recommend filing a bug and attaching the logfiles so >> that this is tracked and evaluated more formally: >> https://bugreport.java.com/bugreport/ >> >> >> If this is indeed a regression, it's important that we get to the >> bottom of it. >> >> Thanks, >> Sean >> >> >> On 6/12/18 11:10 AM, ?????? ???????? wrote: >> >> 2 log files attached. >> >> ?????? ???????? >> >> 2018-06-12 15:40 GMT+03:00 Sean Mullan > > >>: >> >> >> ? ? Please add -Djava.security.debug=certpath to the java >> command line >> ? ? and attach the log file. Preferably, attach 2 log files, >> one for a >> ? ? good run and one for a bad run. This should help show what the >> ? ? problem is. >> >> ? ? --Sean >> >> ? ? On 6/11/18 7:59 PM, ?????? ???????? wrote: >> >> ? ? ? ? Hello. >> ? ? ? ? I tried to use early jdk11 build >> (http://jdk.java.net/11/) - >> ? ? ? ? Oracle JDK build for Windows. >> ? ? ? ? I got exception when my program tries to connect (via >> ? ? ? ? HttpURLConnection) to https://api.vk.com/ >> >> >> sun.security.provider.certpath.SunCertPathBuilderException: >> ? ? ? ? unable to find valid certification path to requested >> target >> ? ? ? ? ???? ?at >> >> sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141) >> ? ? ? ? ~[?:?] >> ? ? ? ? ???? ?at >> >> sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126) >> ? ? ? ? ~[?:?] >> ? ? ? ? ???? ?at >> >> java.security.cert.CertPathBuilder.build(CertPathBuilder.java:297) >> ? ? ? ? ~[?:?] >> ? ? ? ? ???? ?at >> >> sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:380) >> ? ? ? ? ~[?:?] >> ? ? ? ? ???? ?at >> >> sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:290) >> ? ? ? ? ~[?:?] >> ? ? ? ? ???? ?at >> >> sun.security.validator.Validator.validate(Validator.java:264) >> ~[?:?] >> ? ? ? ? ???? ?at >> >> sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:343) >> ? ? ? ? ~[?:?] >> >> ? ? ? ? Same code works well with JDK 10. >> ? ? ? ? Does JDK11 have different set of SSL certificates? Is >> there any >> ? ? ? ? way to allow connection to vk.com >> ? >> >> ? ? ? ? Andrey Turbanov >> >> >> > From markpeloquin at gmail.com Tue Jul 24 18:34:28 2018 From: markpeloquin at gmail.com (Markus Peloquin) Date: Tue, 24 Jul 2018 11:34:28 -0700 Subject: Connection timeouts in JEP 321 (HTTP Client) Message-ID: Somebody pointed me at the upcoming HTTP client implementation, and I'm sad to see that connection timeouts are missing from the implementation (the old HTTP API). Is the absence of connection timeouts intended or an oversight? I'd like to see it added, and it looks like a simple change to me. http://openjdk.java.net/jeps/321 http://mail.openjdk.java.net/pipermail/jdk-dev/2018-March/000996.html There are some environments (such as AWS VPCs), where connection failures are only indicated by a connection timeout. This is because ICMP 'Destination Unreachable' packets are often not forwarded to the client (by load balancers, private links, etc) and there are supposedly some security concerns with allowing them by default. Those ICMP packets give immediate failures (net/host/protocol/port unreachable), but timeouts are slow. The default timeout is unbounded in Java, though the TCP implementation of the OS times-out connection establishment to around 130 seconds. It looks like the implementation uses SocketChannel, which still supports timeouts via chan.socket().connect(addr, timeout). Markus -------------- next part -------------- An HTML attachment was scrubbed... URL: From chris.hegarty at oracle.com Tue Jul 24 20:34:20 2018 From: chris.hegarty at oracle.com (Chris Hegarty) Date: Tue, 24 Jul 2018 21:34:20 +0100 Subject: [PATCH] SOCK_CLOEXEC for opening sockets In-Reply-To: References: <0c24795d-350e-3ac8-4417-0480b41c5c9c@oracle.com> <83f34e37-5cb6-832d-2858-26377d1c8e9d@oracle.com> <3f50f583-a990-fb70-da1d-df2c7b26e08e@oracle.com> <6d445479-e05e-1dcc-fe25-81ee17acb219@oracle.com> Message-ID: <6E376834-21A9-4F2D-B11A-BA2224814444@oracle.com> > On 19 Jul 2018, at 18:41, Andrew Luo wrote: > > Just checking - is there any other changes that I should make to the patch, or anything else you guys need me to do? A webrev genderated from Andrew?s patch along with: 1) some additional includes of ?net_util_md.h? in several missing places in the jdk.net module?s source, as well as the appropriate make change: EXTRA_HEADER_DIRS := \ java.base:libnet, 2) simplified the ifdef structure for NET_Socket and NET_SocketPair in net_util_md.c, and some comment updates, to make it more readable. http://cr.openjdk.java.net/~chegar/8207335/webrev.00/ This successfully passes some preliminary testing, but I will need someone to build / test on AIX. -Chris. P.S. The mailing list seems to have dropped the initial space on the context lines of Andrew?s patch, which I had to restore before it would apply cleanly. From matthias.baesken at sap.com Wed Jul 25 07:13:55 2018 From: matthias.baesken at sap.com (Baesken, Matthias) Date: Wed, 25 Jul 2018 07:13:55 +0000 Subject: RFR : 8205959 : Do not restart close if errno is EINTR Message-ID: Hello, there was some discussion on the topic in the review of https://bugs.openjdk.java.net/browse/JDK-8206145 And an outcome was that at least AIX recommends to repeat the close call on EINTR . Best regards, Matthias > > Message: 4 > Date: Wed, 27 Jun 2018 18:23:36 -0500 > From: David Lloyd > To: Ivan Gerasimov > Cc: net-dev at openjdk.java.net > Subject: Re: RFR : 8205959 : Do not restart close if errno is EINTR > Message-ID: <7706C3A4-9F23-47A2-8196-0D0C40507C0E at redhat.com> > Content-Type: text/plain; charset="us-ascii" > > According to http://man7.org/linux/man-pages/man2/close.2.html it is > currently platform-dependent whether close() must or must not (seems to > be no middle ground) be retried. Might have to do some #ifdef guarding? > > -- > - DML > > > > On Jun 27, 2018, at 6:15 PM, Ivan Gerasimov > wrote: > > > > Hello! > > > > When closing a socket via NET_SocketClose(int fd), a close(fd) is called. > > The later is wrapped in a retry-loop, which is wrong because close() is not > restartable. > > > > The `man 2 close` states: > > """ > > ... close() should not be retried after an EINTR since this may cause a > reused descriptor from another thread to be closed. > > """ > > > > Would you please help review a trivial fix? > > > > BUGURL: https://bugs.openjdk.java.net/browse/JDK-8205959 > > WEBREV: http://cr.openjdk.java.net/~igerasim/8205959/00/webrev/ > > > > Thanks in advance! > > > > -- > > With kind regards, > > Ivan Gerasimov > > > -------------- next part -------------- > An HTML attachment was scrubbed... > URL: dev/attachments/20180627/07adf407/attachment.html> > From Alan.Bateman at oracle.com Wed Jul 25 07:24:35 2018 From: Alan.Bateman at oracle.com (Alan Bateman) Date: Wed, 25 Jul 2018 08:24:35 +0100 Subject: [PATCH] SOCK_CLOEXEC for opening sockets In-Reply-To: <6E376834-21A9-4F2D-B11A-BA2224814444@oracle.com> References: <0c24795d-350e-3ac8-4417-0480b41c5c9c@oracle.com> <83f34e37-5cb6-832d-2858-26377d1c8e9d@oracle.com> <3f50f583-a990-fb70-da1d-df2c7b26e08e@oracle.com> <6d445479-e05e-1dcc-fe25-81ee17acb219@oracle.com> <6E376834-21A9-4F2D-B11A-BA2224814444@oracle.com> Message-ID: <79144fd8-f11f-9384-a81c-a32c368fcd8a@oracle.com> On 24/07/2018 21:34, Chris Hegarty wrote: >> On 19 Jul 2018, at 18:41, Andrew Luo wrote: >> >> Just checking - is there any other changes that I should make to the patch, or anything else you guys need me to do? > A webrev genderated from Andrew?s patch along with: > > 1) some additional includes of ?net_util_md.h? in several missing places > in the jdk.net module?s source, as well as the appropriate make change: > EXTRA_HEADER_DIRS := \ > java.base:libnet, > > 2) simplified the ifdef structure for NET_Socket and NET_SocketPair > in net_util_md.c, and some comment updates, to make it more > readable. > > http://cr.openjdk.java.net/~chegar/8207335/webrev.00/ > Thanks for generating a webrev. As I said previously, the patch isn't complete so native code calling fork/exec may still have to deal with other file descriptors that are inherited into the child. I don't object to doing this in phases of course but somehow we have managed to get by for 20 years without this being an issue. The updates to the various site to use the NET_* functions are fine. However, I think the new functions in net_util_md.c could be cleaner. I think it would be better to fallback to socket/socketpair + fcntl when the initial call fails with EINVAL. -Alan From michael.x.mcmahon at oracle.com Wed Jul 25 08:30:26 2018 From: michael.x.mcmahon at oracle.com (Michael McMahon) Date: Wed, 25 Jul 2018 09:30:26 +0100 Subject: Connection timeouts in JEP 321 (HTTP Client) In-Reply-To: References: Message-ID: <5B583522.5000102@oracle.com> Hi Markus, The API and implementation supports an overall response timeout through the method: HttpRequest.Builder timeout?(Duration duration) So, I don't think any application should be required to wait for 130 seconds. It does not currently have a timeout setting specific for connection setup though. Maybe that is something which could be added in a future release. - Michael. On 24/07/2018, 19:34, Markus Peloquin wrote: > > Somebody pointed me at the upcoming HTTP client implementation, and > I'm sad to see that connection timeouts are missing from the > implementation (the old HTTP API). Is the absence of connection > timeouts intended or an oversight? I'd like to see it added, and it > looks like a simple change to me. > > http://openjdk.java.net/jeps/321 > > http://mail.openjdk.java.net/pipermail/jdk-dev/2018-March/000996.html > > > There are some environments (such as AWS VPCs), where connection > failures are only indicated by a connection timeout. This is because > ICMP 'Destination Unreachable' packets are often not forwarded to the > client (by load balancers, private links, etc) and there are > supposedly some security concerns with allowing them by default. Those > ICMP packets give immediate failures (net/host/protocol/port > unreachable), but timeouts are slow. > > > The default timeout is unbounded in Java, though the TCP > implementation of the OS times-out connection establishment to around > 130 seconds. > > > It looks like the implementation uses SocketChannel, which still > supports timeouts via chan.socket().connect(addr, timeout). > > > Markus > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ecki at zusammenkunft.net Wed Jul 25 09:10:52 2018 From: ecki at zusammenkunft.net (Bernd Eckenfels) Date: Wed, 25 Jul 2018 09:10:52 +0000 Subject: Connection timeouts in JEP 321 (HTTP Client) In-Reply-To: <5B583522.5000102@oracle.com> References: , <5B583522.5000102@oracle.com> Message-ID: Hello, I think the overall request Timeout is not a good substitute (if it applies to connect or DNS at all). Typically you want a small connect Timeout to allow failover or retry and a larger request Timeout to allow long running activities. However propagating the request Timeout (shortened) to the default connect Timeout would be an additional improvement independent from the socket connect timeout. Gruss Bernd -- http://bernd.eckenfels.net ________________________________ Von: -1022778048m Auftrag von Gesendet: Mittwoch, Juli 25, 2018 11:00 AM An: Markus Peloquin Cc: net-dev at openjdk.java.net Betreff: Re: Connection timeouts in JEP 321 (HTTP Client) Hi Markus, The API and implementation supports an overall response timeout through the method: HttpRequest.Builder timeout?(Duration duration) So, I don't think any application should be required to wait for 130 seconds. It does not currently have a timeout setting specific for connection setup though. Maybe that is something which could be added in a future release. - Michael. On 24/07/2018, 19:34, Markus Peloquin wrote: Somebody pointed me at the upcoming HTTP client implementation, and I'm sad to see that connection timeouts are missing from the implementation (the old HTTP API). Is the absence of connection timeouts intended or an oversight? I'd like to see it added, and it looks like a simple change to me. http://openjdk.java.net/jeps/321 http://mail.openjdk.java.net/pipermail/jdk-dev/2018-March/000996.html There are some environments (such as AWS VPCs), where connection failures are only indicated by a connection timeout. This is because ICMP 'Destination Unreachable' packets are often not forwarded to the client (by load balancers, private links, etc) and there are supposedly some security concerns with allowing them by default. Those ICMP packets give immediate failures (net/host/protocol/port unreachable), but timeouts are slow. The default timeout is unbounded in Java, though the TCP implementation of the OS times-out connection establishment to around 130 seconds. It looks like the implementation uses SocketChannel, which still supports timeouts via chan.socket().connect(addr, timeout). Markus -------------- next part -------------- An HTML attachment was scrubbed... URL: From chris.hegarty at oracle.com Wed Jul 25 12:49:37 2018 From: chris.hegarty at oracle.com (Chris Hegarty) Date: Wed, 25 Jul 2018 13:49:37 +0100 Subject: [PATCH] SOCK_CLOEXEC for opening sockets In-Reply-To: <79144fd8-f11f-9384-a81c-a32c368fcd8a@oracle.com> References: <0c24795d-350e-3ac8-4417-0480b41c5c9c@oracle.com> <83f34e37-5cb6-832d-2858-26377d1c8e9d@oracle.com> <3f50f583-a990-fb70-da1d-df2c7b26e08e@oracle.com> <6d445479-e05e-1dcc-fe25-81ee17acb219@oracle.com> <6E376834-21A9-4F2D-B11A-BA2224814444@oracle.com> <79144fd8-f11f-9384-a81c-a32c368fcd8a@oracle.com> Message-ID: <8A6F5B28-8587-48B8-AE58-EFDCEB5D5DD2@oracle.com> Alan, > On 25 Jul 2018, at 08:24, Alan Bateman wrote: > > ... > > As I said previously, the patch isn't complete so native code calling fork/exec may still have to deal with other file descriptors that are inherited into the child. I don't object to doing this in phases of course but somehow we have managed to get by for 20 years without this being an issue. I added the following to the JIRA description to make this clear: "This JIRA issue, by itself, does not completely resolve the problem of native code calling fork/exec, it may still have to deal with other file descriptors that are inherited by the child. Instead this JIRA issue is targeted at the socket and channels areas only, other areas should be tackled on a phased approach though separate JIRA issues." > The updates to the various site to use the NET_* functions are fine. However, I think the new functions in net_util_md.c could be cleaner. I think it would be better to fallback to socket/socketpair + fcntl when the initial call fails with EINVAL. Agreed. How about this ( trying to reduce the ifdef blocks, and keep them relatively clean ) : --- JNIEXPORT int JNICALL NET_Socket(int domain, int type, int protocol) { int s; #if defined(SOCK_CLOEXEC) s = socket(domain, type | SOCK_CLOEXEC, protocol); if (s != -1 || (s == -1 && errno != EINVAL)) { return s; } #endif s = socket(domain, type, protocol); if (s != -1) { // Best effort - return value is intentionally ignored since the socket // was successfully created. fcntl(s, F_SETFD, FD_CLOEXEC); } return s; } --- Updated webrev: http://cr.openjdk.java.net/~chegar/8207335/webrev.01/ -Chris. From chris.hegarty at oracle.com Wed Jul 25 14:43:03 2018 From: chris.hegarty at oracle.com (Chris Hegarty) Date: Wed, 25 Jul 2018 15:43:03 +0100 Subject: Connection timeouts in JEP 321 (HTTP Client) In-Reply-To: References: Message-ID: <4CA92584-6723-4887-A73D-D5741558A0A7@oracle.com> Clearly the request builder `timeout` method can be used to avoid extremely long connection timeouts ( as demonstrated below ), but I see Bernd's call for more fine grained control over various aspects of the request. I'm not opposed to an "HttpRequest.Builder.connectTimeout` method, but this is coming very late in the JDK 11 development cycle. How important is this for 11, given that the naked `timeout` can be used, somewhat, to mitigate against long connection timeouts? $ cat Get.java import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.http.HttpResponse.BodyHandlers; import java.time.Duration; public class Get { public static void main(String[] args) throws Exception { long before = System.nanoTime(); try { HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder(URI.create(args[0])) .timeout(Duration.ofSeconds(10)) .build(); HttpResponse response = client.send(request, BodyHandlers.ofString()); System.out.println("response :" + response); } finally { System.out.println("elapsed secs :" + ((System.nanoTime() - before)/1000_000_000)); } } } $ javac Get.java $ java Get http://example.com:81 elapsed secs :10 Exception in thread "main" java.net.http.HttpTimeoutException: request timed out at java.net.http/jdk.internal.net.http.HttpClientImpl.send(HttpClientImpl.java:551) at java.net.http/jdk.internal.net.http.HttpClientFacade.send(HttpClientFacade.java:113) at Get.main(Get.java:17) -Chris. > On 24 Jul 2018, at 19:34, Markus Peloquin wrote: > > Somebody pointed me at the upcoming HTTP client implementation, and I'm sad to see that connection timeouts are missing from the implementation (the old HTTP API). Is the absence of connection timeouts intended or an oversight? I'd like to see it added, and it looks like a simple change to me. > http://openjdk.java.net/jeps/321 > http://mail.openjdk.java.net/pipermail/jdk-dev/2018-March/000996.html > > There are some environments (such as AWS VPCs), where connection failures are only indicated by a connection timeout. This is because ICMP 'Destination Unreachable' packets are often not forwarded to the client (by load balancers, private links, etc) and there are supposedly some security concerns with allowing them by default. Those ICMP packets give immediate failures (net/host/protocol/port unreachable), but timeouts are slow. > > The default timeout is unbounded in Java, though the TCP implementation of the OS times-out connection establishment to around 130 seconds. > > It looks like the implementation uses SocketChannel, which still supports timeouts via chan.socket().connect(addr, timeout). > > Markus From Alan.Bateman at oracle.com Wed Jul 25 17:58:18 2018 From: Alan.Bateman at oracle.com (Alan Bateman) Date: Wed, 25 Jul 2018 18:58:18 +0100 Subject: [PATCH] SOCK_CLOEXEC for opening sockets In-Reply-To: <8A6F5B28-8587-48B8-AE58-EFDCEB5D5DD2@oracle.com> References: <83f34e37-5cb6-832d-2858-26377d1c8e9d@oracle.com> <3f50f583-a990-fb70-da1d-df2c7b26e08e@oracle.com> <6d445479-e05e-1dcc-fe25-81ee17acb219@oracle.com> <6E376834-21A9-4F2D-B11A-BA2224814444@oracle.com> <79144fd8-f11f-9384-a81c-a32c368fcd8a@oracle.com> <8A6F5B28-8587-48B8-AE58-EFDCEB5D5DD2@oracle.com> Message-ID: <4a3ff399-95ec-ecaa-abec-12c30ea6ce07@oracle.com> On 25/07/2018 13:49, Chris Hegarty wrote: > : >> The updates to the various site to use the NET_* functions are fine. However, I think the new functions in net_util_md.c could be cleaner. I think it would be better to fallback to socket/socketpair + fcntl when the initial call fails with EINVAL. > Agreed. How about this ( trying to reduce the ifdef blocks, and > keep them relatively clean ) : > > --- > JNIEXPORT int JNICALL > NET_Socket(int domain, int type, int protocol) { > int s; > #if defined(SOCK_CLOEXEC) > s = socket(domain, type | SOCK_CLOEXEC, protocol); > if (s != -1 || (s == -1 && errno != EINVAL)) { > return s; > } > #endif > s = socket(domain, type, protocol); > if (s != -1) { > // Best effort - return value is intentionally ignored since the socket > // was successfully created. > fcntl(s, F_SETFD, FD_CLOEXEC); > } > return s; > } > --- > > Updated webrev: > http://cr.openjdk.java.net/~chegar/8207335/webrev.01/ > This looks much better - thanks! -Alan From markpeloquin at gmail.com Wed Jul 25 18:42:13 2018 From: markpeloquin at gmail.com (Markus Ivan Peloquin) Date: Wed, 25 Jul 2018 11:42:13 -0700 Subject: Connection timeouts in JEP 321 (HTTP Client) In-Reply-To: <4CA92584-6723-4887-A73D-D5741558A0A7@oracle.com> References: <4CA92584-6723-4887-A73D-D5741558A0A7@oracle.com> Message-ID: <3a7ce4a8-ef85-ce26-841c-1517320d4b8e@gmail.com> It's unfortunate that the user sees this when a connection wasn't even established: java.net.http.HttpTimeoutException: request timed out Could it use Channel::isOpen to return a more specific exception? HttpConnectionException? Or at least a more specific message. > How important is this for 11 ...? If the question's for me, it's a strong preference. I would prefer to keep my legacy code in place in order to preserve my short connection timeouts and the more specific SocketTimeoutException root cause. I have to diagnose problems using backtraces, and the lack of information makes it difficult. Though I may be okay with something like HttpConnectionException. Markus On 2018-07-25 07:43, Chris Hegarty wrote: > Clearly the request builder `timeout` method can be used to avoid > extremely long connection timeouts ( as demonstrated below ), but I see > Bernd's call for more fine grained control over various aspects of the > request. > > I'm not opposed to an "HttpRequest.Builder.connectTimeout` method, but > this is coming very late in the JDK 11 development cycle. How important > is this for 11, given that the naked `timeout` can be used, somewhat, to > mitigate against long connection timeouts? > > > $ cat Get.java > > import java.net.URI; > import java.net.http.HttpClient; > import java.net.http.HttpRequest; > import java.net.http.HttpResponse; > import java.net.http.HttpResponse.BodyHandlers; > import java.time.Duration; > > public class Get { > public static void main(String[] args) throws Exception { > long before = System.nanoTime(); > try { > HttpClient client = HttpClient.newHttpClient(); > HttpRequest request = HttpRequest.newBuilder(URI.create(args[0])) > .timeout(Duration.ofSeconds(10)) > .build(); > HttpResponse response = client.send(request, BodyHandlers.ofString()); > System.out.println("response :" + response); > } finally { > System.out.println("elapsed secs :" + ((System.nanoTime() - before)/1000_000_000)); > } > } > } > $ javac Get.java > $ java Get http://example.com:81 > elapsed secs :10 > Exception in thread "main" java.net.http.HttpTimeoutException: request timed out > at java.net.http/jdk.internal.net.http.HttpClientImpl.send(HttpClientImpl.java:551) > at java.net.http/jdk.internal.net.http.HttpClientFacade.send(HttpClientFacade.java:113) > at Get.main(Get.java:17) > > -Chris. > >> On 24 Jul 2018, at 19:34, Markus Peloquin wrote: >> >> Somebody pointed me at the upcoming HTTP client implementation, and I'm sad to see that connection timeouts are missing from the implementation (the old HTTP API). Is the absence of connection timeouts intended or an oversight? I'd like to see it added, and it looks like a simple change to me. >> http://openjdk.java.net/jeps/321 >> http://mail.openjdk.java.net/pipermail/jdk-dev/2018-March/000996.html >> >> There are some environments (such as AWS VPCs), where connection failures are only indicated by a connection timeout. This is because ICMP 'Destination Unreachable' packets are often not forwarded to the client (by load balancers, private links, etc) and there are supposedly some security concerns with allowing them by default. Those ICMP packets give immediate failures (net/host/protocol/port unreachable), but timeouts are slow. >> >> The default timeout is unbounded in Java, though the TCP implementation of the OS times-out connection establishment to around 130 seconds. >> >> It looks like the implementation uses SocketChannel, which still supports timeouts via chan.socket().connect(addr, timeout). >> >> Markus From ivan.gerasimov at oracle.com Thu Jul 26 05:04:04 2018 From: ivan.gerasimov at oracle.com (Ivan Gerasimov) Date: Wed, 25 Jul 2018 22:04:04 -0700 Subject: [PATCH] SOCK_CLOEXEC for opening sockets In-Reply-To: <8A6F5B28-8587-48B8-AE58-EFDCEB5D5DD2@oracle.com> References: <83f34e37-5cb6-832d-2858-26377d1c8e9d@oracle.com> <3f50f583-a990-fb70-da1d-df2c7b26e08e@oracle.com> <6d445479-e05e-1dcc-fe25-81ee17acb219@oracle.com> <6E376834-21A9-4F2D-B11A-BA2224814444@oracle.com> <79144fd8-f11f-9384-a81c-a32c368fcd8a@oracle.com> <8A6F5B28-8587-48B8-AE58-EFDCEB5D5DD2@oracle.com> Message-ID: <700d8570-b8c6-9406-1204-8d4507610fab@oracle.com> Hi Chris! A couple of minor comments. 1) if (s != -1 || (s == -1 && errno != EINVAL)) { This can be simplified to if (s != -1 || errno != EINVAL) { 2) What about sockets created with accept(): Shouldn't NET_Accept be modified to set O_CLOEXEC as well? On Linux accept4() can be used to pass SOCK_CLOEXEC flag. With kind regards, Ivan On 7/25/18 5:49 AM, Chris Hegarty wrote: > Alan, > >> On 25 Jul 2018, at 08:24, Alan Bateman wrote: >> >> ... >> >> As I said previously, the patch isn't complete so native code calling fork/exec may still have to deal with other file descriptors that are inherited into the child. I don't object to doing this in phases of course but somehow we have managed to get by for 20 years without this being an issue. > I added the following to the JIRA description to make this clear: > > "This JIRA issue, by itself, does not completely resolve the problem > of native code calling fork/exec, it may still have to deal with other > file descriptors that are inherited by the child. Instead this JIRA > issue is targeted at the socket and channels areas only, other areas > should be tackled on a phased approach though separate JIRA > issues." > >> The updates to the various site to use the NET_* functions are fine. However, I think the new functions in net_util_md.c could be cleaner. I think it would be better to fallback to socket/socketpair + fcntl when the initial call fails with EINVAL. > Agreed. How about this ( trying to reduce the ifdef blocks, and > keep them relatively clean ) : > > --- > JNIEXPORT int JNICALL > NET_Socket(int domain, int type, int protocol) { > int s; > #if defined(SOCK_CLOEXEC) > s = socket(domain, type | SOCK_CLOEXEC, protocol); > if (s != -1 || (s == -1 && errno != EINVAL)) { > return s; > } > #endif > s = socket(domain, type, protocol); > if (s != -1) { > // Best effort - return value is intentionally ignored since the socket > // was successfully created. > fcntl(s, F_SETFD, FD_CLOEXEC); > } > return s; > } > --- > > Updated webrev: > http://cr.openjdk.java.net/~chegar/8207335/webrev.01/ > > -Chris. -- With kind regards, Ivan Gerasimov From david.lloyd at redhat.com Thu Jul 26 18:20:11 2018 From: david.lloyd at redhat.com (David Lloyd) Date: Thu, 26 Jul 2018 13:20:11 -0500 Subject: Connection timeouts in JEP 321 (HTTP Client) In-Reply-To: <4CA92584-6723-4887-A73D-D5741558A0A7@oracle.com> References: <4CA92584-6723-4887-A73D-D5741558A0A7@oracle.com> Message-ID: On Wed, Jul 25, 2018 at 9:43 AM Chris Hegarty wrote: > > Clearly the request builder `timeout` method can be used to avoid > extremely long connection timeouts ( as demonstrated below ), but I see > Bernd's call for more fine grained control over various aspects of the > request. > > I'm not opposed to an "HttpRequest.Builder.connectTimeout` method, but > this is coming very late in the JDK 11 development cycle. How important > is this for 11, given that the naked `timeout` can be used, somewhat, to > mitigate against long connection timeouts? FWIW I think this is a design error (one that I have made in multiple areas in the past) and should be rectified ASAP. It is becoming increasingly evident (to me at least) that it is important to distinguish between connection and request timeouts, especially for protocols like HTTP where connections may be reused. Connection mutliplexing and reuse means that the first request has a different overall disposition than subsequent requests. The semantics of a connection failure may be substantially different from a request failure, and as was previously pointed out, different architectures have different tolerances for the two that may not align easily. -- - DML From andrewluotechnologies at outlook.com Thu Jul 26 18:30:52 2018 From: andrewluotechnologies at outlook.com (Andrew Luo) Date: Thu, 26 Jul 2018 18:30:52 +0000 Subject: [PATCH] SOCK_CLOEXEC for opening sockets In-Reply-To: <700d8570-b8c6-9406-1204-8d4507610fab@oracle.com> References: <83f34e37-5cb6-832d-2858-26377d1c8e9d@oracle.com> <3f50f583-a990-fb70-da1d-df2c7b26e08e@oracle.com> <6d445479-e05e-1dcc-fe25-81ee17acb219@oracle.com> <6E376834-21A9-4F2D-B11A-BA2224814444@oracle.com> <79144fd8-f11f-9384-a81c-a32c368fcd8a@oracle.com> <8A6F5B28-8587-48B8-AE58-EFDCEB5D5DD2@oracle.com> <700d8570-b8c6-9406-1204-8d4507610fab@oracle.com> Message-ID: Do we need to support compiling on a newer kernel with newer headers and then running the compiled binaries on an older platform? If so, then I think we probably have to use dlsym to call accept4 at runtime rather than compile time... Thanks, -Andrew -----Original Message----- From: net-dev On Behalf Of Ivan Gerasimov Sent: Wednesday, July 25, 2018 10:04 PM To: Chris Hegarty Cc: net-dev at openjdk.java.net Subject: Re: [PATCH] SOCK_CLOEXEC for opening sockets Hi Chris! A couple of minor comments. 1) if (s != -1 || (s == -1 && errno != EINVAL)) { This can be simplified to if (s != -1 || errno != EINVAL) { 2) What about sockets created with accept(): Shouldn't NET_Accept be modified to set O_CLOEXEC as well? On Linux accept4() can be used to pass SOCK_CLOEXEC flag. With kind regards, Ivan On 7/25/18 5:49 AM, Chris Hegarty wrote: > Alan, > >> On 25 Jul 2018, at 08:24, Alan Bateman wrote: >> >> ... >> >> As I said previously, the patch isn't complete so native code calling fork/exec may still have to deal with other file descriptors that are inherited into the child. I don't object to doing this in phases of course but somehow we have managed to get by for 20 years without this being an issue. > I added the following to the JIRA description to make this clear: > > "This JIRA issue, by itself, does not completely resolve the problem > of native code calling fork/exec, it may still have to deal with other > file descriptors that are inherited by the child. Instead this JIRA > issue is targeted at the socket and channels areas only, other areas > should be tackled on a phased approach though separate JIRA issues." > >> The updates to the various site to use the NET_* functions are fine. However, I think the new functions in net_util_md.c could be cleaner. I think it would be better to fallback to socket/socketpair + fcntl when the initial call fails with EINVAL. > Agreed. How about this ( trying to reduce the ifdef blocks, and keep > them relatively clean ) : > > --- > JNIEXPORT int JNICALL > NET_Socket(int domain, int type, int protocol) { > int s; > #if defined(SOCK_CLOEXEC) > s = socket(domain, type | SOCK_CLOEXEC, protocol); > if (s != -1 || (s == -1 && errno != EINVAL)) { > return s; > } > #endif > s = socket(domain, type, protocol); > if (s != -1) { > // Best effort - return value is intentionally ignored since the socket > // was successfully created. > fcntl(s, F_SETFD, FD_CLOEXEC); > } > return s; > } > --- > > Updated webrev: > http://cr.openjdk.java.net/~chegar/8207335/webrev.01/ > > -Chris. -- With kind regards, Ivan Gerasimov From chris.hegarty at oracle.com Thu Jul 26 21:14:44 2018 From: chris.hegarty at oracle.com (Chris Hegarty) Date: Thu, 26 Jul 2018 22:14:44 +0100 Subject: Connection timeouts in JEP 321 (HTTP Client) In-Reply-To: References: <4CA92584-6723-4887-A73D-D5741558A0A7@oracle.com> Message-ID: <431D3856-41D1-40A2-828C-AB37B0AD2842@oracle.com> I?m giving this serious consideration, and will reply more comprehensively within the next couple of days. -Chris > On 26 Jul 2018, at 19:20, David Lloyd wrote: > >> On Wed, Jul 25, 2018 at 9:43 AM Chris Hegarty wrote: >> >> Clearly the request builder `timeout` method can be used to avoid >> extremely long connection timeouts ( as demonstrated below ), but I see >> Bernd's call for more fine grained control over various aspects of the >> request. >> >> I'm not opposed to an "HttpRequest.Builder.connectTimeout` method, but >> this is coming very late in the JDK 11 development cycle. How important >> is this for 11, given that the naked `timeout` can be used, somewhat, to >> mitigate against long connection timeouts? > > FWIW I think this is a design error (one that I have made in multiple > areas in the past) and should be rectified ASAP. It is becoming > increasingly evident (to me at least) that it is important to > distinguish between connection and request timeouts, especially for > protocols like HTTP where connections may be reused. Connection > mutliplexing and reuse means that the first request has a different > overall disposition than subsequent requests. The semantics of a > connection failure may be substantially different from a request > failure, and as was previously pointed out, different architectures > have different tolerances for the two that may not align easily. > > -- > - DML From xuelei.fan at oracle.com Mon Jul 30 17:24:45 2018 From: xuelei.fan at oracle.com (Xuelei Fan) Date: Mon, 30 Jul 2018 10:24:45 -0700 Subject: Code Review Request, JDK-8207009 SSLEngine#closeInbound mentions SSLException when no close_notify is received In-Reply-To: <99d6eeaf-f77b-1967-10be-92347273b794@oracle.com> References: <99d6eeaf-f77b-1967-10be-92347273b794@oracle.com> Message-ID: Please let me know your concerns by the end of August 1st, 2018. Thanks, Xuelei On 7/30/2018 9:59 AM, Xuelei Fan wrote: > Hi, > > Please review the update for the TLS 1.3 half-close and synchronization > implementation: > ?? http://cr.openjdk.java.net/~xuelei/8207009/webrev.00/ > > Unlike TLS 1.2 and prior versions, for TLS 1.3, the close_notify is use > to close the local write side and peer read side only.? After the > close_notify get handles, the local read side and peer write side may > still be open. > > In this update, if an application calls > SSLEngine.closeInbound/Outbound() or SSLSocket.shutdownInput/Output(), > half-close will be used.? For compatibility, if SSLSocket.close() get > called, a duplex close will be tried.? In order to support duplex close, > JDK will use the user_canceled warning alert even the handshake complete. > > In practice, an application may only close outbound even it is intended > to close the inbound as well, or close the connection completely.? It > works for TLS 1.2 and prior versions.? But no more for TLS 1.3 because > of the close_notify behavior change in the TLS 1.3 specification.? The > application may be hung and dead-waiting for read/close.? It could be > solved by closing the inbound explicitly.? In order to mitigate the > impact, a new System Property is introduced, > "jdk.tls.acknowledgeCloseNotify" if source code update is not available. > ?If the System Property is set to "true", if receiving the > close_notify, a close_notify alert will be responded.? It is a > countermeasure of the TLS 1.3 half-close issues. > > Thanks, > Xuelei > > > From andrewluotechnologies at outlook.com Tue Jul 31 00:08:15 2018 From: andrewluotechnologies at outlook.com (Andrew Luo) Date: Tue, 31 Jul 2018 00:08:15 +0000 Subject: [PATCH] SOCK_CLOEXEC for opening sockets In-Reply-To: References: <83f34e37-5cb6-832d-2858-26377d1c8e9d@oracle.com> <3f50f583-a990-fb70-da1d-df2c7b26e08e@oracle.com> <6d445479-e05e-1dcc-fe25-81ee17acb219@oracle.com> <6E376834-21A9-4F2D-B11A-BA2224814444@oracle.com> <79144fd8-f11f-9384-a81c-a32c368fcd8a@oracle.com> <8A6F5B28-8587-48B8-AE58-EFDCEB5D5DD2@oracle.com> <700d8570-b8c6-9406-1204-8d4507610fab@oracle.com> Message-ID: I've updated my patch. Let me know if this approach looks good to you. I'm using dlsym to get the function pointer to accept4 at runtime so we can support compiling on newer Linux systems and using the binaries on older Linux systems (where the newer Linux system has accept4, and the older Linux system does not). I know I still need to edit the other Unix (Solaris, AIX, BSD) files but I wanted to put this out there first to see if the approach looks good. diff --git a/make/lib/Lib-jdk.net.gmk b/make/lib/Lib-jdk.net.gmk --- a/make/lib/Lib-jdk.net.gmk +++ b/make/lib/Lib-jdk.net.gmk @@ -33,9 +33,11 @@ NAME := extnet, \ OPTIMIZATION := LOW, \ CFLAGS := $(CFLAGS_JDKLIB), \ + EXTRA_HEADER_DIRS := \ + java.base:libnet, \ LDFLAGS := $(LDFLAGS_JDKLIB) \ $(call SET_SHARED_LIBRARY_ORIGIN), \ - LIBS := -ljava, \ + LIBS := -ljava -lnet, \ LIBS_solaris := -lsocket, \ LIBS_linux := -ljvm, \ )) diff --git a/src/java.base/aix/native/libnio/ch/AixPollPort.c b/src/java.base/aix/native/libnio/ch/AixPollPort.c --- a/src/java.base/aix/native/libnio/ch/AixPollPort.c +++ b/src/java.base/aix/native/libnio/ch/AixPollPort.c @@ -30,6 +30,7 @@ #include "jlong.h" #include "sun_nio_ch_AixPollPort.h" +#include "net_util_md.h" #include #include @@ -137,7 +138,7 @@ JNIEXPORT void JNICALL Java_sun_nio_ch_AixPollPort_socketpair(JNIEnv* env, jclass clazz, jintArray sv) { int sp[2]; - if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) == -1) { + if (NET_SocketPair(PF_UNIX, SOCK_STREAM, 0, sp) == -1) { JNU_ThrowIOExceptionWithLastError(env, "socketpair failed"); } else { jint res[2]; diff --git a/src/java.base/linux/native/libnet/linux_close.c b/src/java.base/linux/native/libnet/linux_close.c --- a/src/java.base/linux/native/libnet/linux_close.c +++ b/src/java.base/linux/native/libnet/linux_close.c @@ -24,6 +24,7 @@ */ #include +#include #include #include #include @@ -395,7 +396,31 @@ BLOCKING_IO_RETURN_INT( s, sendto(s, msg, len, flags, to, tolen) ); } -int NET_Accept(int s, struct sockaddr *addr, socklen_t *addrlen) { +static int acceptFcntlCloexec(int s, struct sockaddr *addr, socklen_t *addrlen) { + int cs; + cs = accept(s, addr, addrlen); + if (cs != -1) { + // Best effort - return value is intentionally ignored since the connected + // socket was successfully created. + fcntl(cs, F_SETFD, FD_CLOEXEC); + } + return cs; +} + +JNIEXPORT int JNICALL +NET_Accept(int s, struct sockaddr *addr, socklen_t *addrlen) { + static int (*accept4functionpointer)(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags) = NULL; + static int accept4initialized = 0; + int cs; + + if (!accept4initialized) { + accept4functionpointer = dlsym(RTLD_DEFAULT, "accept4"); + accept4initialized = 1; + } + + if (accept4functionpointer != NULL) { + BLOCKING_IO_RETURN_INT( s, accept4functionpointer(s, addr, addrlen, SOCK_CLOEXEC) ); + } BLOCKING_IO_RETURN_INT( s, accept(s, addr, addrlen) ); } diff --git a/src/java.base/unix/native/libnet/Inet4AddressImpl.c b/src/java.base/unix/native/libnet/Inet4AddressImpl.c --- a/src/java.base/unix/native/libnet/Inet4AddressImpl.c +++ b/src/java.base/unix/native/libnet/Inet4AddressImpl.c @@ -264,7 +264,7 @@ int connect_rv = -1; // open a TCP socket - fd = socket(AF_INET, SOCK_STREAM, 0); + fd = NET_Socket(AF_INET, SOCK_STREAM, 0); if (fd == -1) { // note: if you run out of fds, you may not be able to load // the exception class, and get a NoClassDefFoundError instead. @@ -503,7 +503,7 @@ // Let's try to create a RAW socket to send ICMP packets. // This usually requires "root" privileges, so it's likely to fail. - fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); + fd = NET_Socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); if (fd == -1) { return tcp_ping4(env, &sa, netif, timeout, ttl); } else { diff --git a/src/java.base/unix/native/libnet/Inet6AddressImpl.c b/src/java.base/unix/native/libnet/Inet6AddressImpl.c --- a/src/java.base/unix/native/libnet/Inet6AddressImpl.c +++ b/src/java.base/unix/native/libnet/Inet6AddressImpl.c @@ -461,7 +461,7 @@ int connect_rv = -1; // open a TCP socket - fd = socket(AF_INET6, SOCK_STREAM, 0); + fd = NET_Socket(AF_INET6, SOCK_STREAM, 0); if (fd == -1) { // note: if you run out of fds, you may not be able to load // the exception class, and get a NoClassDefFoundError instead. @@ -711,7 +711,7 @@ // Let's try to create a RAW socket to send ICMP packets. // This usually requires "root" privileges, so it's likely to fail. - fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); + fd = NET_Socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); if (fd == -1) { return tcp_ping6(env, &sa, netif, timeout, ttl); } else { diff --git a/src/java.base/unix/native/libnet/NetworkInterface.c b/src/java.base/unix/native/libnet/NetworkInterface.c --- a/src/java.base/unix/native/libnet/NetworkInterface.c +++ b/src/java.base/unix/native/libnet/NetworkInterface.c @@ -1055,7 +1055,7 @@ static int openSocket(JNIEnv *env, int proto) { int sock; - if ((sock = socket(proto, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(proto, SOCK_DGRAM, 0)) < 0) { // If EPROTONOSUPPORT is returned it means we don't have // support for this proto so don't throw an exception. if (errno != EPROTONOSUPPORT) { @@ -1078,9 +1078,9 @@ static int openSocketWithFallback(JNIEnv *env, const char *ifname) { int sock; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) { if (errno == EPROTONOSUPPORT) { - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; @@ -1315,9 +1315,9 @@ static int openSocketWithFallback(JNIEnv *env, const char *ifname) { int sock; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) { if (errno == EPROTONOSUPPORT) { - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; @@ -1590,9 +1590,9 @@ int sock, alreadyV6 = 0; struct lifreq if2; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) { if (errno == EPROTONOSUPPORT) { - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; @@ -1616,7 +1616,7 @@ strncpy(if2.lifr_name, ifname, sizeof(if2.lifr_name) - 1); if (ioctl(sock, SIOCGLIFNETMASK, (char *)&if2) < 0) { close(sock); - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; @@ -1941,9 +1941,9 @@ static int openSocketWithFallback(JNIEnv *env, const char *ifname) { int sock; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) { if (errno == EPROTONOSUPPORT) { - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; diff --git a/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c b/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c --- a/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c +++ b/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c @@ -904,7 +904,7 @@ return; } - if ((fd = socket(domain, SOCK_DGRAM, 0)) == -1) { + if ((fd = NET_Socket(domain, SOCK_DGRAM, 0)) == -1) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "Error creating socket"); return; diff --git a/src/java.base/unix/native/libnet/PlainSocketImpl.c b/src/java.base/unix/native/libnet/PlainSocketImpl.c --- a/src/java.base/unix/native/libnet/PlainSocketImpl.c +++ b/src/java.base/unix/native/libnet/PlainSocketImpl.c @@ -77,7 +77,7 @@ int sv[2]; #ifdef AF_UNIX - if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == -1) { + if (NET_SocketPair(AF_UNIX, SOCK_STREAM, 0, sv) == -1) { return -1; } #else @@ -178,7 +178,7 @@ return; } - if ((fd = socket(domain, type, 0)) == -1) { + if ((fd = NET_Socket(domain, type, 0)) == -1) { /* note: if you run out of fds, you may not be able to load * the exception class, and get a NoClassDefFoundError * instead. diff --git a/src/java.base/unix/native/libnet/SdpSupport.c b/src/java.base/unix/native/libnet/SdpSupport.c --- a/src/java.base/unix/native/libnet/SdpSupport.c +++ b/src/java.base/unix/native/libnet/SdpSupport.c @@ -57,7 +57,7 @@ #if defined(__solaris__) int domain = ipv6_available() ? AF_INET6 : AF_INET; - s = socket(domain, SOCK_STREAM, PROTO_SDP); + s = NET_Socket(domain, SOCK_STREAM, PROTO_SDP); #elif defined(__linux__) /** * IPv6 not supported by SDP on Linux @@ -66,7 +66,7 @@ JNU_ThrowIOException(env, "IPv6 not supported"); return -1; } - s = socket(AF_INET_SDP, SOCK_STREAM, 0); + s = NET_Socket(AF_INET_SDP, SOCK_STREAM, 0); #else /* not supported on other platforms at this time */ s = -1; diff --git a/src/java.base/unix/native/libnet/net_util_md.c b/src/java.base/unix/native/libnet/net_util_md.c --- a/src/java.base/unix/native/libnet/net_util_md.c +++ b/src/java.base/unix/native/libnet/net_util_md.c @@ -131,6 +131,52 @@ return (result == -1) ? 0 : 1; } + /* + * Creates a socket. + * Uses SOCK_CLOEXEC during creation or FD_CLOEXEC post-creation, where possible + * and on a best-effort basis, on systems that support it. + */ + JNIEXPORT int JNICALL + NET_Socket(int domain, int type, int protocol) { + int s; + #if defined(SOCK_CLOEXEC) + s = socket(domain, type | SOCK_CLOEXEC, protocol); + if (s != -1 || (s == -1 && errno != EINVAL)) { + return s; + } + #endif + s = socket(domain, type, protocol); + if (s != -1) { + // Best effort - return value is intentionally ignored since the socket + // was successfully created. + fcntl(s, F_SETFD, FD_CLOEXEC); + } + return s; + } + +/* + * Creates a pair of connected sockets. + * Uses SOCK_CLOEXEC during creation or FD_CLOEXEC post-creation, where possible + * and on a best-effort basis, on systems that support it. + */ +JNIEXPORT int JNICALL +NET_SocketPair(int domain, int type, int protocol, int socket_vector[2]) { + int s; +#if defined(SOCK_CLOEXEC) + s = socketpair(domain, type | SOCK_CLOEXEC, protocol, socket_vector); + if (s != -1 || (s == -1 && errno != EINVAL)) { + return s; + } +#endif + s = socketpair(domain, type, protocol, socket_vector); + if (s != -1) { + // Best effort - return value is intentionally ignored since the socket + // was successfully created. + fcntl(s, F_SETFD, FD_CLOEXEC); + } + return s; +} + #ifdef __solaris__ static int init_tcp_max_buf, init_udp_max_buf; static int tcp_max_buf; @@ -295,7 +341,7 @@ SOCKETADDRESS sa; socklen_t sa_len = sizeof(SOCKETADDRESS); - fd = socket(AF_INET6, SOCK_STREAM, 0) ; + fd = NET_Socket(AF_INET6, SOCK_STREAM, 0) ; if (fd < 0) { /* * TODO: We really cant tell since it may be an unrelated error @@ -402,7 +448,7 @@ /* Do a simple dummy call, and try to figure out from that */ int one = 1; int rv, s; - s = socket(PF_INET, SOCK_STREAM, 0); + s = NET_Socket(PF_INET, SOCK_STREAM, 0); if (s < 0) { return JNI_FALSE; } diff --git a/src/java.base/unix/native/libnet/net_util_md.h b/src/java.base/unix/native/libnet/net_util_md.h --- a/src/java.base/unix/native/libnet/net_util_md.h +++ b/src/java.base/unix/native/libnet/net_util_md.h @@ -77,6 +77,9 @@ * Functions */ +JNIEXPORT int JNICALL NET_Socket(int domain, int type, int protocol); +JNIEXPORT int JNICALL NET_SocketPair(int domain, int type, int protocol, int socket_vector[2]); + int NET_Timeout(JNIEnv *env, int s, long timeout, jlong nanoTimeStamp); int NET_Read(int s, void* buf, size_t len); int NET_NonBlockingRead(int s, void* buf, size_t len); @@ -88,7 +91,7 @@ flags, const struct sockaddr *to, int tolen); int NET_Writev(int s, const struct iovec * vector, int count); int NET_Connect(int s, struct sockaddr *addr, int addrlen); -int NET_Accept(int s, struct sockaddr *addr, socklen_t *addrlen); +JNIEXPORT int JNICALL NET_Accept(int s, struct sockaddr *addr, socklen_t *addrlen); int NET_SocketClose(int s); int NET_Dup2(int oldfd, int newfd); int NET_Poll(struct pollfd *ufds, unsigned int nfds, int timeout); diff --git a/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c b/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c --- a/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c +++ b/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c @@ -56,6 +56,7 @@ #include "jlong.h" #include "nio.h" #include "nio_util.h" +#include "net_util_md.h" #include "sun_nio_ch_FileDispatcherImpl.h" #include "java_lang_Long.h" @@ -67,7 +68,7 @@ Java_sun_nio_ch_FileDispatcherImpl_init(JNIEnv *env, jclass cl) { int sp[2]; - if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) { + if (NET_SocketPair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) { JNU_ThrowIOExceptionWithLastError(env, "socketpair failed"); return; } diff --git a/src/java.base/unix/native/libnio/ch/Net.c b/src/java.base/unix/native/libnio/ch/Net.c --- a/src/java.base/unix/native/libnio/ch/Net.c +++ b/src/java.base/unix/native/libnio/ch/Net.c @@ -198,7 +198,7 @@ int type = (stream ? SOCK_STREAM : SOCK_DGRAM); int domain = (ipv6_available() && preferIPv6) ? AF_INET6 : AF_INET; - fd = socket(domain, type, 0); + fd = NET_Socket(domain, type, 0); if (fd < 0) { return handleSocketError(env, errno); } diff --git a/src/java.base/unix/native/libnio/ch/ServerSocketChannelImpl.c b/src/java.base/unix/native/libnio/ch/ServerSocketChannelImpl.c --- a/src/java.base/unix/native/libnio/ch/ServerSocketChannelImpl.c +++ b/src/java.base/unix/native/libnio/ch/ServerSocketChannelImpl.c @@ -92,7 +92,7 @@ * accept() was called. */ for (;;) { - newfd = accept(ssfd, &sa.sa, &sa_len); + newfd = NET_Accept(ssfd, &sa.sa, &sa_len); if (newfd >= 0) { break; } diff --git a/src/jdk.net/linux/native/libextnet/LinuxSocketOptions.c b/src/jdk.net/linux/native/libextnet/LinuxSocketOptions.c --- a/src/jdk.net/linux/native/libextnet/LinuxSocketOptions.c +++ b/src/jdk.net/linux/native/libextnet/LinuxSocketOptions.c @@ -31,6 +31,7 @@ #include #include #include "jni_util.h" +#include "net_util_md.h" #include "jdk_net_LinuxSocketOptions.h" /* @@ -86,7 +87,7 @@ (JNIEnv *env, jobject unused) { int one = 1; int rv, s; - s = socket(PF_INET, SOCK_STREAM, 0); + s = NET_Socket(PF_INET, SOCK_STREAM, 0); if (s < 0) { return JNI_FALSE; } @@ -103,7 +104,7 @@ static jint socketOptionSupported(jint sockopt) { jint one = 1; jint rv, s; - s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + s = NET_Socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (s < 0) { return 0; } diff --git a/src/jdk.net/macosx/native/libextnet/MacOSXSocketOptions.c b/src/jdk.net/macosx/native/libextnet/MacOSXSocketOptions.c --- a/src/jdk.net/macosx/native/libextnet/MacOSXSocketOptions.c +++ b/src/jdk.net/macosx/native/libextnet/MacOSXSocketOptions.c @@ -31,11 +31,12 @@ #include #include #include "jni_util.h" +#include "net_util_md.h" static jint socketOptionSupported(jint sockopt) { jint one = 1; jint rv, s; - s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + s = NET_Socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (s < 0) { return 0; } diff --git a/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.c b/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.c --- a/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.c +++ b/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.c @@ -157,7 +157,7 @@ sock_flow_props_t props; int rv, s; - s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + s = NET_Socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (s < 0) { return JNI_FALSE; } diff --git a/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.h b/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.h --- a/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.h +++ b/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.h @@ -36,6 +36,7 @@ #include "jdk_net_SocketFlow.h" #include "SolarisSocketOptions.h" #include "jdk_net_SolarisSocketOptions.h" +#include "net_util_md.h" #ifndef SO_FLOW_SLA #define SO_FLOW_SLA 0x1018 diff --git a/src/jdk.sctp/unix/native/libsctp/SctpNet.c b/src/jdk.sctp/unix/native/libsctp/SctpNet.c --- a/src/jdk.sctp/unix/native/libsctp/SctpNet.c +++ b/src/jdk.sctp/unix/native/libsctp/SctpNet.c @@ -151,7 +151,7 @@ Java_sun_nio_ch_sctp_SctpNet_init (JNIEnv *env, jclass cl) { int sp[2]; - if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) { + if (NET_SocketPair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) { JNU_ThrowIOExceptionWithLastError(env, "socketpair failed"); return; } @@ -180,7 +180,7 @@ return 0; } - fd = socket(domain, (oneToOne ? SOCK_STREAM : SOCK_SEQPACKET), IPPROTO_SCTP); + fd = NET_Socket(domain, (oneToOne ? SOCK_STREAM : SOCK_SEQPACKET), IPPROTO_SCTP); if (fd < 0) { return handleSocketError(env, errno); Thanks, -Andrew -----Original Message----- From: net-dev On Behalf Of Andrew Luo Sent: Thursday, July 26, 2018 11:31 AM To: Ivan Gerasimov ; Chris Hegarty Cc: net-dev at openjdk.java.net Subject: RE: [PATCH] SOCK_CLOEXEC for opening sockets Do we need to support compiling on a newer kernel with newer headers and then running the compiled binaries on an older platform? If so, then I think we probably have to use dlsym to call accept4 at runtime rather than compile time... Thanks, -Andrew -----Original Message----- From: net-dev On Behalf Of Ivan Gerasimov Sent: Wednesday, July 25, 2018 10:04 PM To: Chris Hegarty Cc: net-dev at openjdk.java.net Subject: Re: [PATCH] SOCK_CLOEXEC for opening sockets Hi Chris! A couple of minor comments. 1) if (s != -1 || (s == -1 && errno != EINVAL)) { This can be simplified to if (s != -1 || errno != EINVAL) { 2) What about sockets created with accept(): Shouldn't NET_Accept be modified to set O_CLOEXEC as well? On Linux accept4() can be used to pass SOCK_CLOEXEC flag. With kind regards, Ivan On 7/25/18 5:49 AM, Chris Hegarty wrote: > Alan, > >> On 25 Jul 2018, at 08:24, Alan Bateman wrote: >> >> ... >> >> As I said previously, the patch isn't complete so native code calling fork/exec may still have to deal with other file descriptors that are inherited into the child. I don't object to doing this in phases of course but somehow we have managed to get by for 20 years without this being an issue. > I added the following to the JIRA description to make this clear: > > "This JIRA issue, by itself, does not completely resolve the problem > of native code calling fork/exec, it may still have to deal with other > file descriptors that are inherited by the child. Instead this JIRA > issue is targeted at the socket and channels areas only, other areas > should be tackled on a phased approach though separate JIRA issues." > >> The updates to the various site to use the NET_* functions are fine. However, I think the new functions in net_util_md.c could be cleaner. I think it would be better to fallback to socket/socketpair + fcntl when the initial call fails with EINVAL. > Agreed. How about this ( trying to reduce the ifdef blocks, and keep > them relatively clean ) : > > --- > JNIEXPORT int JNICALL > NET_Socket(int domain, int type, int protocol) { > int s; > #if defined(SOCK_CLOEXEC) > s = socket(domain, type | SOCK_CLOEXEC, protocol); > if (s != -1 || (s == -1 && errno != EINVAL)) { > return s; > } > #endif > s = socket(domain, type, protocol); > if (s != -1) { > // Best effort - return value is intentionally ignored since the socket > // was successfully created. > fcntl(s, F_SETFD, FD_CLOEXEC); > } > return s; > } > --- > > Updated webrev: > http://cr.openjdk.java.net/~chegar/8207335/webrev.01/ > > -Chris. -- With kind regards, Ivan Gerasimov From andrewluotechnologies at outlook.com Tue Jul 31 04:44:04 2018 From: andrewluotechnologies at outlook.com (Andrew Luo) Date: Tue, 31 Jul 2018 04:44:04 +0000 Subject: [PATCH] SOCK_CLOEXEC for opening sockets In-Reply-To: References: <83f34e37-5cb6-832d-2858-26377d1c8e9d@oracle.com> <3f50f583-a990-fb70-da1d-df2c7b26e08e@oracle.com> <6d445479-e05e-1dcc-fe25-81ee17acb219@oracle.com> <6E376834-21A9-4F2D-B11A-BA2224814444@oracle.com> <79144fd8-f11f-9384-a81c-a32c368fcd8a@oracle.com> <8A6F5B28-8587-48B8-AE58-EFDCEB5D5DD2@oracle.com> <700d8570-b8c6-9406-1204-8d4507610fab@oracle.com> Message-ID: Fixed a bug, updated (I was calling accept directly instead of a helper function that calls accept then fcntl): diff --git a/make/lib/Lib-jdk.net.gmk b/make/lib/Lib-jdk.net.gmk --- a/make/lib/Lib-jdk.net.gmk +++ b/make/lib/Lib-jdk.net.gmk @@ -33,9 +33,11 @@ NAME := extnet, \ OPTIMIZATION := LOW, \ CFLAGS := $(CFLAGS_JDKLIB), \ + EXTRA_HEADER_DIRS := \ + java.base:libnet, \ LDFLAGS := $(LDFLAGS_JDKLIB) \ $(call SET_SHARED_LIBRARY_ORIGIN), \ - LIBS := -ljava, \ + LIBS := -ljava -lnet, \ LIBS_solaris := -lsocket, \ LIBS_linux := -ljvm, \ )) diff --git a/src/java.base/aix/native/libnio/ch/AixPollPort.c b/src/java.base/aix/native/libnio/ch/AixPollPort.c --- a/src/java.base/aix/native/libnio/ch/AixPollPort.c +++ b/src/java.base/aix/native/libnio/ch/AixPollPort.c @@ -30,6 +30,7 @@ #include "jlong.h" #include "sun_nio_ch_AixPollPort.h" +#include "net_util_md.h" #include #include @@ -137,7 +138,7 @@ JNIEXPORT void JNICALL Java_sun_nio_ch_AixPollPort_socketpair(JNIEnv* env, jclass clazz, jintArray sv) { int sp[2]; - if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) == -1) { + if (NET_SocketPair(PF_UNIX, SOCK_STREAM, 0, sp) == -1) { JNU_ThrowIOExceptionWithLastError(env, "socketpair failed"); } else { jint res[2]; diff --git a/src/java.base/linux/native/libnet/linux_close.c b/src/java.base/linux/native/libnet/linux_close.c --- a/src/java.base/linux/native/libnet/linux_close.c +++ b/src/java.base/linux/native/libnet/linux_close.c @@ -24,6 +24,7 @@ */ #include +#include #include #include #include @@ -395,8 +396,32 @@ BLOCKING_IO_RETURN_INT( s, sendto(s, msg, len, flags, to, tolen) ); } -int NET_Accept(int s, struct sockaddr *addr, socklen_t *addrlen) { - BLOCKING_IO_RETURN_INT( s, accept(s, addr, addrlen) ); +static int acceptFcntlCloexec(int s, struct sockaddr *addr, socklen_t *addrlen) { + int cs; + cs = accept(s, addr, addrlen); + if (cs != -1) { + // Best effort - return value is intentionally ignored since the connected + // socket was successfully created. + fcntl(cs, F_SETFD, FD_CLOEXEC); + } + return cs; +} + +JNIEXPORT int JNICALL +NET_Accept(int s, struct sockaddr *addr, socklen_t *addrlen) { + static int (*accept4functionpointer)(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags) = NULL; + static int accept4initialized = 0; + int cs; + + if (!accept4initialized) { + accept4functionpointer = dlsym(RTLD_DEFAULT, "accept4"); + accept4initialized = 1; + } + + if (accept4functionpointer != NULL) { + BLOCKING_IO_RETURN_INT( s, accept4functionpointer(s, addr, addrlen, SOCK_CLOEXEC) ); + } + BLOCKING_IO_RETURN_INT( s, acceptFcntlCloexec(s, addr, addrlen) ); } int NET_Connect(int s, struct sockaddr *addr, int addrlen) { diff --git a/src/java.base/unix/native/libnet/Inet4AddressImpl.c b/src/java.base/unix/native/libnet/Inet4AddressImpl.c --- a/src/java.base/unix/native/libnet/Inet4AddressImpl.c +++ b/src/java.base/unix/native/libnet/Inet4AddressImpl.c @@ -264,7 +264,7 @@ int connect_rv = -1; // open a TCP socket - fd = socket(AF_INET, SOCK_STREAM, 0); + fd = NET_Socket(AF_INET, SOCK_STREAM, 0); if (fd == -1) { // note: if you run out of fds, you may not be able to load // the exception class, and get a NoClassDefFoundError instead. @@ -503,7 +503,7 @@ // Let's try to create a RAW socket to send ICMP packets. // This usually requires "root" privileges, so it's likely to fail. - fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); + fd = NET_Socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); if (fd == -1) { return tcp_ping4(env, &sa, netif, timeout, ttl); } else { diff --git a/src/java.base/unix/native/libnet/Inet6AddressImpl.c b/src/java.base/unix/native/libnet/Inet6AddressImpl.c --- a/src/java.base/unix/native/libnet/Inet6AddressImpl.c +++ b/src/java.base/unix/native/libnet/Inet6AddressImpl.c @@ -461,7 +461,7 @@ int connect_rv = -1; // open a TCP socket - fd = socket(AF_INET6, SOCK_STREAM, 0); + fd = NET_Socket(AF_INET6, SOCK_STREAM, 0); if (fd == -1) { // note: if you run out of fds, you may not be able to load // the exception class, and get a NoClassDefFoundError instead. @@ -711,7 +711,7 @@ // Let's try to create a RAW socket to send ICMP packets. // This usually requires "root" privileges, so it's likely to fail. - fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); + fd = NET_Socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); if (fd == -1) { return tcp_ping6(env, &sa, netif, timeout, ttl); } else { diff --git a/src/java.base/unix/native/libnet/NetworkInterface.c b/src/java.base/unix/native/libnet/NetworkInterface.c --- a/src/java.base/unix/native/libnet/NetworkInterface.c +++ b/src/java.base/unix/native/libnet/NetworkInterface.c @@ -1055,7 +1055,7 @@ static int openSocket(JNIEnv *env, int proto) { int sock; - if ((sock = socket(proto, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(proto, SOCK_DGRAM, 0)) < 0) { // If EPROTONOSUPPORT is returned it means we don't have // support for this proto so don't throw an exception. if (errno != EPROTONOSUPPORT) { @@ -1078,9 +1078,9 @@ static int openSocketWithFallback(JNIEnv *env, const char *ifname) { int sock; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) { if (errno == EPROTONOSUPPORT) { - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; @@ -1315,9 +1315,9 @@ static int openSocketWithFallback(JNIEnv *env, const char *ifname) { int sock; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) { if (errno == EPROTONOSUPPORT) { - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; @@ -1590,9 +1590,9 @@ int sock, alreadyV6 = 0; struct lifreq if2; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) { if (errno == EPROTONOSUPPORT) { - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; @@ -1616,7 +1616,7 @@ strncpy(if2.lifr_name, ifname, sizeof(if2.lifr_name) - 1); if (ioctl(sock, SIOCGLIFNETMASK, (char *)&if2) < 0) { close(sock); - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; @@ -1941,9 +1941,9 @@ static int openSocketWithFallback(JNIEnv *env, const char *ifname) { int sock; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) { if (errno == EPROTONOSUPPORT) { - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; diff --git a/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c b/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c --- a/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c +++ b/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c @@ -904,7 +904,7 @@ return; } - if ((fd = socket(domain, SOCK_DGRAM, 0)) == -1) { + if ((fd = NET_Socket(domain, SOCK_DGRAM, 0)) == -1) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "Error creating socket"); return; diff --git a/src/java.base/unix/native/libnet/PlainSocketImpl.c b/src/java.base/unix/native/libnet/PlainSocketImpl.c --- a/src/java.base/unix/native/libnet/PlainSocketImpl.c +++ b/src/java.base/unix/native/libnet/PlainSocketImpl.c @@ -77,7 +77,7 @@ int sv[2]; #ifdef AF_UNIX - if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == -1) { + if (NET_SocketPair(AF_UNIX, SOCK_STREAM, 0, sv) == -1) { return -1; } #else @@ -178,7 +178,7 @@ return; } - if ((fd = socket(domain, type, 0)) == -1) { + if ((fd = NET_Socket(domain, type, 0)) == -1) { /* note: if you run out of fds, you may not be able to load * the exception class, and get a NoClassDefFoundError * instead. diff --git a/src/java.base/unix/native/libnet/SdpSupport.c b/src/java.base/unix/native/libnet/SdpSupport.c --- a/src/java.base/unix/native/libnet/SdpSupport.c +++ b/src/java.base/unix/native/libnet/SdpSupport.c @@ -57,7 +57,7 @@ #if defined(__solaris__) int domain = ipv6_available() ? AF_INET6 : AF_INET; - s = socket(domain, SOCK_STREAM, PROTO_SDP); + s = NET_Socket(domain, SOCK_STREAM, PROTO_SDP); #elif defined(__linux__) /** * IPv6 not supported by SDP on Linux @@ -66,7 +66,7 @@ JNU_ThrowIOException(env, "IPv6 not supported"); return -1; } - s = socket(AF_INET_SDP, SOCK_STREAM, 0); + s = NET_Socket(AF_INET_SDP, SOCK_STREAM, 0); #else /* not supported on other platforms at this time */ s = -1; diff --git a/src/java.base/unix/native/libnet/net_util_md.c b/src/java.base/unix/native/libnet/net_util_md.c --- a/src/java.base/unix/native/libnet/net_util_md.c +++ b/src/java.base/unix/native/libnet/net_util_md.c @@ -131,6 +131,52 @@ return (result == -1) ? 0 : 1; } + /* + * Creates a socket. + * Uses SOCK_CLOEXEC during creation or FD_CLOEXEC post-creation, where possible + * and on a best-effort basis, on systems that support it. + */ + JNIEXPORT int JNICALL + NET_Socket(int domain, int type, int protocol) { + int s; + #if defined(SOCK_CLOEXEC) + s = socket(domain, type | SOCK_CLOEXEC, protocol); + if (s != -1 || (s == -1 && errno != EINVAL)) { + return s; + } + #endif + s = socket(domain, type, protocol); + if (s != -1) { + // Best effort - return value is intentionally ignored since the socket + // was successfully created. + fcntl(s, F_SETFD, FD_CLOEXEC); + } + return s; + } + +/* + * Creates a pair of connected sockets. + * Uses SOCK_CLOEXEC during creation or FD_CLOEXEC post-creation, where possible + * and on a best-effort basis, on systems that support it. + */ +JNIEXPORT int JNICALL +NET_SocketPair(int domain, int type, int protocol, int socket_vector[2]) { + int s; +#if defined(SOCK_CLOEXEC) + s = socketpair(domain, type | SOCK_CLOEXEC, protocol, socket_vector); + if (s != -1 || (s == -1 && errno != EINVAL)) { + return s; + } +#endif + s = socketpair(domain, type, protocol, socket_vector); + if (s != -1) { + // Best effort - return value is intentionally ignored since the socket + // was successfully created. + fcntl(s, F_SETFD, FD_CLOEXEC); + } + return s; +} + #ifdef __solaris__ static int init_tcp_max_buf, init_udp_max_buf; static int tcp_max_buf; @@ -295,7 +341,7 @@ SOCKETADDRESS sa; socklen_t sa_len = sizeof(SOCKETADDRESS); - fd = socket(AF_INET6, SOCK_STREAM, 0) ; + fd = NET_Socket(AF_INET6, SOCK_STREAM, 0) ; if (fd < 0) { /* * TODO: We really cant tell since it may be an unrelated error @@ -402,7 +448,7 @@ /* Do a simple dummy call, and try to figure out from that */ int one = 1; int rv, s; - s = socket(PF_INET, SOCK_STREAM, 0); + s = NET_Socket(PF_INET, SOCK_STREAM, 0); if (s < 0) { return JNI_FALSE; } diff --git a/src/java.base/unix/native/libnet/net_util_md.h b/src/java.base/unix/native/libnet/net_util_md.h --- a/src/java.base/unix/native/libnet/net_util_md.h +++ b/src/java.base/unix/native/libnet/net_util_md.h @@ -77,6 +77,9 @@ * Functions */ +JNIEXPORT int JNICALL NET_Socket(int domain, int type, int protocol); +JNIEXPORT int JNICALL NET_SocketPair(int domain, int type, int protocol, int socket_vector[2]); + int NET_Timeout(JNIEnv *env, int s, long timeout, jlong nanoTimeStamp); int NET_Read(int s, void* buf, size_t len); int NET_NonBlockingRead(int s, void* buf, size_t len); @@ -88,7 +91,7 @@ flags, const struct sockaddr *to, int tolen); int NET_Writev(int s, const struct iovec * vector, int count); int NET_Connect(int s, struct sockaddr *addr, int addrlen); -int NET_Accept(int s, struct sockaddr *addr, socklen_t *addrlen); +JNIEXPORT int JNICALL NET_Accept(int s, struct sockaddr *addr, socklen_t *addrlen); int NET_SocketClose(int s); int NET_Dup2(int oldfd, int newfd); int NET_Poll(struct pollfd *ufds, unsigned int nfds, int timeout); diff --git a/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c b/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c --- a/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c +++ b/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c @@ -56,6 +56,7 @@ #include "jlong.h" #include "nio.h" #include "nio_util.h" +#include "net_util_md.h" #include "sun_nio_ch_FileDispatcherImpl.h" #include "java_lang_Long.h" @@ -67,7 +68,7 @@ Java_sun_nio_ch_FileDispatcherImpl_init(JNIEnv *env, jclass cl) { int sp[2]; - if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) { + if (NET_SocketPair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) { JNU_ThrowIOExceptionWithLastError(env, "socketpair failed"); return; } diff --git a/src/java.base/unix/native/libnio/ch/Net.c b/src/java.base/unix/native/libnio/ch/Net.c --- a/src/java.base/unix/native/libnio/ch/Net.c +++ b/src/java.base/unix/native/libnio/ch/Net.c @@ -198,7 +198,7 @@ int type = (stream ? SOCK_STREAM : SOCK_DGRAM); int domain = (ipv6_available() && preferIPv6) ? AF_INET6 : AF_INET; - fd = socket(domain, type, 0); + fd = NET_Socket(domain, type, 0); if (fd < 0) { return handleSocketError(env, errno); } diff --git a/src/java.base/unix/native/libnio/ch/ServerSocketChannelImpl.c b/src/java.base/unix/native/libnio/ch/ServerSocketChannelImpl.c --- a/src/java.base/unix/native/libnio/ch/ServerSocketChannelImpl.c +++ b/src/java.base/unix/native/libnio/ch/ServerSocketChannelImpl.c @@ -92,7 +92,7 @@ * accept() was called. */ for (;;) { - newfd = accept(ssfd, &sa.sa, &sa_len); + newfd = NET_Accept(ssfd, &sa.sa, &sa_len); if (newfd >= 0) { break; } diff --git a/src/jdk.net/linux/native/libextnet/LinuxSocketOptions.c b/src/jdk.net/linux/native/libextnet/LinuxSocketOptions.c --- a/src/jdk.net/linux/native/libextnet/LinuxSocketOptions.c +++ b/src/jdk.net/linux/native/libextnet/LinuxSocketOptions.c @@ -31,6 +31,7 @@ #include #include #include "jni_util.h" +#include "net_util_md.h" #include "jdk_net_LinuxSocketOptions.h" /* @@ -86,7 +87,7 @@ (JNIEnv *env, jobject unused) { int one = 1; int rv, s; - s = socket(PF_INET, SOCK_STREAM, 0); + s = NET_Socket(PF_INET, SOCK_STREAM, 0); if (s < 0) { return JNI_FALSE; } @@ -103,7 +104,7 @@ static jint socketOptionSupported(jint sockopt) { jint one = 1; jint rv, s; - s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + s = NET_Socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (s < 0) { return 0; } diff --git a/src/jdk.net/macosx/native/libextnet/MacOSXSocketOptions.c b/src/jdk.net/macosx/native/libextnet/MacOSXSocketOptions.c --- a/src/jdk.net/macosx/native/libextnet/MacOSXSocketOptions.c +++ b/src/jdk.net/macosx/native/libextnet/MacOSXSocketOptions.c @@ -31,11 +31,12 @@ #include #include #include "jni_util.h" +#include "net_util_md.h" static jint socketOptionSupported(jint sockopt) { jint one = 1; jint rv, s; - s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + s = NET_Socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (s < 0) { return 0; } diff --git a/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.c b/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.c --- a/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.c +++ b/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.c @@ -157,7 +157,7 @@ sock_flow_props_t props; int rv, s; - s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + s = NET_Socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (s < 0) { return JNI_FALSE; } diff --git a/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.h b/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.h --- a/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.h +++ b/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.h @@ -36,6 +36,7 @@ #include "jdk_net_SocketFlow.h" #include "SolarisSocketOptions.h" #include "jdk_net_SolarisSocketOptions.h" +#include "net_util_md.h" #ifndef SO_FLOW_SLA #define SO_FLOW_SLA 0x1018 diff --git a/src/jdk.sctp/unix/native/libsctp/SctpNet.c b/src/jdk.sctp/unix/native/libsctp/SctpNet.c --- a/src/jdk.sctp/unix/native/libsctp/SctpNet.c +++ b/src/jdk.sctp/unix/native/libsctp/SctpNet.c @@ -151,7 +151,7 @@ Java_sun_nio_ch_sctp_SctpNet_init (JNIEnv *env, jclass cl) { int sp[2]; - if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) { + if (NET_SocketPair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) { JNU_ThrowIOExceptionWithLastError(env, "socketpair failed"); return; } @@ -180,7 +180,7 @@ return 0; } - fd = socket(domain, (oneToOne ? SOCK_STREAM : SOCK_SEQPACKET), IPPROTO_SCTP); + fd = NET_Socket(domain, (oneToOne ? SOCK_STREAM : SOCK_SEQPACKET), IPPROTO_SCTP); if (fd < 0) { return handleSocketError(env, errno); Thanks, -Andrew -----Original Message----- From: Andrew Luo Sent: Monday, July 30, 2018 5:08 PM To: Andrew Luo ; Ivan Gerasimov ; Chris Hegarty Cc: net-dev at openjdk.java.net Subject: RE: [PATCH] SOCK_CLOEXEC for opening sockets I've updated my patch. Let me know if this approach looks good to you. I'm using dlsym to get the function pointer to accept4 at runtime so we can support compiling on newer Linux systems and using the binaries on older Linux systems (where the newer Linux system has accept4, and the older Linux system does not). I know I still need to edit the other Unix (Solaris, AIX, BSD) files but I wanted to put this out there first to see if the approach looks good. diff --git a/make/lib/Lib-jdk.net.gmk b/make/lib/Lib-jdk.net.gmk --- a/make/lib/Lib-jdk.net.gmk +++ b/make/lib/Lib-jdk.net.gmk @@ -33,9 +33,11 @@ NAME := extnet, \ OPTIMIZATION := LOW, \ CFLAGS := $(CFLAGS_JDKLIB), \ + EXTRA_HEADER_DIRS := \ + java.base:libnet, \ LDFLAGS := $(LDFLAGS_JDKLIB) \ $(call SET_SHARED_LIBRARY_ORIGIN), \ - LIBS := -ljava, \ + LIBS := -ljava -lnet, \ LIBS_solaris := -lsocket, \ LIBS_linux := -ljvm, \ )) diff --git a/src/java.base/aix/native/libnio/ch/AixPollPort.c b/src/java.base/aix/native/libnio/ch/AixPollPort.c --- a/src/java.base/aix/native/libnio/ch/AixPollPort.c +++ b/src/java.base/aix/native/libnio/ch/AixPollPort.c @@ -30,6 +30,7 @@ #include "jlong.h" #include "sun_nio_ch_AixPollPort.h" +#include "net_util_md.h" #include #include @@ -137,7 +138,7 @@ JNIEXPORT void JNICALL Java_sun_nio_ch_AixPollPort_socketpair(JNIEnv* env, jclass clazz, jintArray sv) { int sp[2]; - if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) == -1) { + if (NET_SocketPair(PF_UNIX, SOCK_STREAM, 0, sp) == -1) { JNU_ThrowIOExceptionWithLastError(env, "socketpair failed"); } else { jint res[2]; diff --git a/src/java.base/linux/native/libnet/linux_close.c b/src/java.base/linux/native/libnet/linux_close.c --- a/src/java.base/linux/native/libnet/linux_close.c +++ b/src/java.base/linux/native/libnet/linux_close.c @@ -24,6 +24,7 @@ */ #include +#include #include #include #include @@ -395,7 +396,31 @@ BLOCKING_IO_RETURN_INT( s, sendto(s, msg, len, flags, to, tolen) ); } -int NET_Accept(int s, struct sockaddr *addr, socklen_t *addrlen) { +static int acceptFcntlCloexec(int s, struct sockaddr *addr, socklen_t *addrlen) { + int cs; + cs = accept(s, addr, addrlen); + if (cs != -1) { + // Best effort - return value is intentionally ignored since the connected + // socket was successfully created. + fcntl(cs, F_SETFD, FD_CLOEXEC); + } + return cs; +} + +JNIEXPORT int JNICALL +NET_Accept(int s, struct sockaddr *addr, socklen_t *addrlen) { + static int (*accept4functionpointer)(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags) = NULL; + static int accept4initialized = 0; + int cs; + + if (!accept4initialized) { + accept4functionpointer = dlsym(RTLD_DEFAULT, "accept4"); + accept4initialized = 1; + } + + if (accept4functionpointer != NULL) { + BLOCKING_IO_RETURN_INT( s, accept4functionpointer(s, addr, addrlen, SOCK_CLOEXEC) ); + } BLOCKING_IO_RETURN_INT( s, accept(s, addr, addrlen) ); } diff --git a/src/java.base/unix/native/libnet/Inet4AddressImpl.c b/src/java.base/unix/native/libnet/Inet4AddressImpl.c --- a/src/java.base/unix/native/libnet/Inet4AddressImpl.c +++ b/src/java.base/unix/native/libnet/Inet4AddressImpl.c @@ -264,7 +264,7 @@ int connect_rv = -1; // open a TCP socket - fd = socket(AF_INET, SOCK_STREAM, 0); + fd = NET_Socket(AF_INET, SOCK_STREAM, 0); if (fd == -1) { // note: if you run out of fds, you may not be able to load // the exception class, and get a NoClassDefFoundError instead. @@ -503,7 +503,7 @@ // Let's try to create a RAW socket to send ICMP packets. // This usually requires "root" privileges, so it's likely to fail. - fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); + fd = NET_Socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); if (fd == -1) { return tcp_ping4(env, &sa, netif, timeout, ttl); } else { diff --git a/src/java.base/unix/native/libnet/Inet6AddressImpl.c b/src/java.base/unix/native/libnet/Inet6AddressImpl.c --- a/src/java.base/unix/native/libnet/Inet6AddressImpl.c +++ b/src/java.base/unix/native/libnet/Inet6AddressImpl.c @@ -461,7 +461,7 @@ int connect_rv = -1; // open a TCP socket - fd = socket(AF_INET6, SOCK_STREAM, 0); + fd = NET_Socket(AF_INET6, SOCK_STREAM, 0); if (fd == -1) { // note: if you run out of fds, you may not be able to load // the exception class, and get a NoClassDefFoundError instead. @@ -711,7 +711,7 @@ // Let's try to create a RAW socket to send ICMP packets. // This usually requires "root" privileges, so it's likely to fail. - fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); + fd = NET_Socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); if (fd == -1) { return tcp_ping6(env, &sa, netif, timeout, ttl); } else { diff --git a/src/java.base/unix/native/libnet/NetworkInterface.c b/src/java.base/unix/native/libnet/NetworkInterface.c --- a/src/java.base/unix/native/libnet/NetworkInterface.c +++ b/src/java.base/unix/native/libnet/NetworkInterface.c @@ -1055,7 +1055,7 @@ static int openSocket(JNIEnv *env, int proto) { int sock; - if ((sock = socket(proto, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(proto, SOCK_DGRAM, 0)) < 0) { // If EPROTONOSUPPORT is returned it means we don't have // support for this proto so don't throw an exception. if (errno != EPROTONOSUPPORT) { @@ -1078,9 +1078,9 @@ static int openSocketWithFallback(JNIEnv *env, const char *ifname) { int sock; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) { if (errno == EPROTONOSUPPORT) { - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; @@ -1315,9 +1315,9 @@ static int openSocketWithFallback(JNIEnv *env, const char *ifname) { int sock; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) { if (errno == EPROTONOSUPPORT) { - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; @@ -1590,9 +1590,9 @@ int sock, alreadyV6 = 0; struct lifreq if2; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) { if (errno == EPROTONOSUPPORT) { - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; @@ -1616,7 +1616,7 @@ strncpy(if2.lifr_name, ifname, sizeof(if2.lifr_name) - 1); if (ioctl(sock, SIOCGLIFNETMASK, (char *)&if2) < 0) { close(sock); - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; @@ -1941,9 +1941,9 @@ static int openSocketWithFallback(JNIEnv *env, const char *ifname) { int sock; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) { if (errno == EPROTONOSUPPORT) { - if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + if ((sock = NET_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); return -1; diff --git a/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c b/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c --- a/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c +++ b/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c @@ -904,7 +904,7 @@ return; } - if ((fd = socket(domain, SOCK_DGRAM, 0)) == -1) { + if ((fd = NET_Socket(domain, SOCK_DGRAM, 0)) == -1) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "Error creating socket"); return; diff --git a/src/java.base/unix/native/libnet/PlainSocketImpl.c b/src/java.base/unix/native/libnet/PlainSocketImpl.c --- a/src/java.base/unix/native/libnet/PlainSocketImpl.c +++ b/src/java.base/unix/native/libnet/PlainSocketImpl.c @@ -77,7 +77,7 @@ int sv[2]; #ifdef AF_UNIX - if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == -1) { + if (NET_SocketPair(AF_UNIX, SOCK_STREAM, 0, sv) == -1) { return -1; } #else @@ -178,7 +178,7 @@ return; } - if ((fd = socket(domain, type, 0)) == -1) { + if ((fd = NET_Socket(domain, type, 0)) == -1) { /* note: if you run out of fds, you may not be able to load * the exception class, and get a NoClassDefFoundError * instead. diff --git a/src/java.base/unix/native/libnet/SdpSupport.c b/src/java.base/unix/native/libnet/SdpSupport.c --- a/src/java.base/unix/native/libnet/SdpSupport.c +++ b/src/java.base/unix/native/libnet/SdpSupport.c @@ -57,7 +57,7 @@ #if defined(__solaris__) int domain = ipv6_available() ? AF_INET6 : AF_INET; - s = socket(domain, SOCK_STREAM, PROTO_SDP); + s = NET_Socket(domain, SOCK_STREAM, PROTO_SDP); #elif defined(__linux__) /** * IPv6 not supported by SDP on Linux @@ -66,7 +66,7 @@ JNU_ThrowIOException(env, "IPv6 not supported"); return -1; } - s = socket(AF_INET_SDP, SOCK_STREAM, 0); + s = NET_Socket(AF_INET_SDP, SOCK_STREAM, 0); #else /* not supported on other platforms at this time */ s = -1; diff --git a/src/java.base/unix/native/libnet/net_util_md.c b/src/java.base/unix/native/libnet/net_util_md.c --- a/src/java.base/unix/native/libnet/net_util_md.c +++ b/src/java.base/unix/native/libnet/net_util_md.c @@ -131,6 +131,52 @@ return (result == -1) ? 0 : 1; } + /* + * Creates a socket. + * Uses SOCK_CLOEXEC during creation or FD_CLOEXEC post-creation, + where possible + * and on a best-effort basis, on systems that support it. + */ + JNIEXPORT int JNICALL + NET_Socket(int domain, int type, int protocol) { + int s; + #if defined(SOCK_CLOEXEC) + s = socket(domain, type | SOCK_CLOEXEC, protocol); + if (s != -1 || (s == -1 && errno != EINVAL)) { + return s; + } + #endif + s = socket(domain, type, protocol); + if (s != -1) { + // Best effort - return value is intentionally ignored since the socket + // was successfully created. + fcntl(s, F_SETFD, FD_CLOEXEC); + } + return s; + } + +/* + * Creates a pair of connected sockets. + * Uses SOCK_CLOEXEC during creation or FD_CLOEXEC post-creation, where +possible + * and on a best-effort basis, on systems that support it. + */ +JNIEXPORT int JNICALL +NET_SocketPair(int domain, int type, int protocol, int socket_vector[2]) { + int s; +#if defined(SOCK_CLOEXEC) + s = socketpair(domain, type | SOCK_CLOEXEC, protocol, socket_vector); + if (s != -1 || (s == -1 && errno != EINVAL)) { + return s; + } +#endif + s = socketpair(domain, type, protocol, socket_vector); + if (s != -1) { + // Best effort - return value is intentionally ignored since the socket + // was successfully created. + fcntl(s, F_SETFD, FD_CLOEXEC); + } + return s; +} + #ifdef __solaris__ static int init_tcp_max_buf, init_udp_max_buf; static int tcp_max_buf; @@ -295,7 +341,7 @@ SOCKETADDRESS sa; socklen_t sa_len = sizeof(SOCKETADDRESS); - fd = socket(AF_INET6, SOCK_STREAM, 0) ; + fd = NET_Socket(AF_INET6, SOCK_STREAM, 0) ; if (fd < 0) { /* * TODO: We really cant tell since it may be an unrelated error @@ -402,7 +448,7 @@ /* Do a simple dummy call, and try to figure out from that */ int one = 1; int rv, s; - s = socket(PF_INET, SOCK_STREAM, 0); + s = NET_Socket(PF_INET, SOCK_STREAM, 0); if (s < 0) { return JNI_FALSE; } diff --git a/src/java.base/unix/native/libnet/net_util_md.h b/src/java.base/unix/native/libnet/net_util_md.h --- a/src/java.base/unix/native/libnet/net_util_md.h +++ b/src/java.base/unix/native/libnet/net_util_md.h @@ -77,6 +77,9 @@ * Functions */ +JNIEXPORT int JNICALL NET_Socket(int domain, int type, int protocol); +JNIEXPORT int JNICALL NET_SocketPair(int domain, int type, int +protocol, int socket_vector[2]); + int NET_Timeout(JNIEnv *env, int s, long timeout, jlong nanoTimeStamp); int NET_Read(int s, void* buf, size_t len); int NET_NonBlockingRead(int s, void* buf, size_t len); @@ -88,7 +91,7 @@ flags, const struct sockaddr *to, int tolen); int NET_Writev(int s, const struct iovec * vector, int count); int NET_Connect(int s, struct sockaddr *addr, int addrlen); -int NET_Accept(int s, struct sockaddr *addr, socklen_t *addrlen); +JNIEXPORT int JNICALL NET_Accept(int s, struct sockaddr *addr, +socklen_t *addrlen); int NET_SocketClose(int s); int NET_Dup2(int oldfd, int newfd); int NET_Poll(struct pollfd *ufds, unsigned int nfds, int timeout); diff --git a/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c b/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c --- a/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c +++ b/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c @@ -56,6 +56,7 @@ #include "jlong.h" #include "nio.h" #include "nio_util.h" +#include "net_util_md.h" #include "sun_nio_ch_FileDispatcherImpl.h" #include "java_lang_Long.h" @@ -67,7 +68,7 @@ Java_sun_nio_ch_FileDispatcherImpl_init(JNIEnv *env, jclass cl) { int sp[2]; - if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) { + if (NET_SocketPair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) { JNU_ThrowIOExceptionWithLastError(env, "socketpair failed"); return; } diff --git a/src/java.base/unix/native/libnio/ch/Net.c b/src/java.base/unix/native/libnio/ch/Net.c --- a/src/java.base/unix/native/libnio/ch/Net.c +++ b/src/java.base/unix/native/libnio/ch/Net.c @@ -198,7 +198,7 @@ int type = (stream ? SOCK_STREAM : SOCK_DGRAM); int domain = (ipv6_available() && preferIPv6) ? AF_INET6 : AF_INET; - fd = socket(domain, type, 0); + fd = NET_Socket(domain, type, 0); if (fd < 0) { return handleSocketError(env, errno); } diff --git a/src/java.base/unix/native/libnio/ch/ServerSocketChannelImpl.c b/src/java.base/unix/native/libnio/ch/ServerSocketChannelImpl.c --- a/src/java.base/unix/native/libnio/ch/ServerSocketChannelImpl.c +++ b/src/java.base/unix/native/libnio/ch/ServerSocketChannelImpl.c @@ -92,7 +92,7 @@ * accept() was called. */ for (;;) { - newfd = accept(ssfd, &sa.sa, &sa_len); + newfd = NET_Accept(ssfd, &sa.sa, &sa_len); if (newfd >= 0) { break; } diff --git a/src/jdk.net/linux/native/libextnet/LinuxSocketOptions.c b/src/jdk.net/linux/native/libextnet/LinuxSocketOptions.c --- a/src/jdk.net/linux/native/libextnet/LinuxSocketOptions.c +++ b/src/jdk.net/linux/native/libextnet/LinuxSocketOptions.c @@ -31,6 +31,7 @@ #include #include #include "jni_util.h" +#include "net_util_md.h" #include "jdk_net_LinuxSocketOptions.h" /* @@ -86,7 +87,7 @@ (JNIEnv *env, jobject unused) { int one = 1; int rv, s; - s = socket(PF_INET, SOCK_STREAM, 0); + s = NET_Socket(PF_INET, SOCK_STREAM, 0); if (s < 0) { return JNI_FALSE; } @@ -103,7 +104,7 @@ static jint socketOptionSupported(jint sockopt) { jint one = 1; jint rv, s; - s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + s = NET_Socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (s < 0) { return 0; } diff --git a/src/jdk.net/macosx/native/libextnet/MacOSXSocketOptions.c b/src/jdk.net/macosx/native/libextnet/MacOSXSocketOptions.c --- a/src/jdk.net/macosx/native/libextnet/MacOSXSocketOptions.c +++ b/src/jdk.net/macosx/native/libextnet/MacOSXSocketOptions.c @@ -31,11 +31,12 @@ #include #include #include "jni_util.h" +#include "net_util_md.h" static jint socketOptionSupported(jint sockopt) { jint one = 1; jint rv, s; - s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + s = NET_Socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (s < 0) { return 0; } diff --git a/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.c b/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.c --- a/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.c +++ b/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.c @@ -157,7 +157,7 @@ sock_flow_props_t props; int rv, s; - s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + s = NET_Socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (s < 0) { return JNI_FALSE; } diff --git a/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.h b/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.h --- a/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.h +++ b/src/jdk.net/solaris/native/libextnet/SolarisSocketOptions.h @@ -36,6 +36,7 @@ #include "jdk_net_SocketFlow.h" #include "SolarisSocketOptions.h" #include "jdk_net_SolarisSocketOptions.h" +#include "net_util_md.h" #ifndef SO_FLOW_SLA #define SO_FLOW_SLA 0x1018 diff --git a/src/jdk.sctp/unix/native/libsctp/SctpNet.c b/src/jdk.sctp/unix/native/libsctp/SctpNet.c --- a/src/jdk.sctp/unix/native/libsctp/SctpNet.c +++ b/src/jdk.sctp/unix/native/libsctp/SctpNet.c @@ -151,7 +151,7 @@ Java_sun_nio_ch_sctp_SctpNet_init (JNIEnv *env, jclass cl) { int sp[2]; - if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) { + if (NET_SocketPair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) { JNU_ThrowIOExceptionWithLastError(env, "socketpair failed"); return; } @@ -180,7 +180,7 @@ return 0; } - fd = socket(domain, (oneToOne ? SOCK_STREAM : SOCK_SEQPACKET), IPPROTO_SCTP); + fd = NET_Socket(domain, (oneToOne ? SOCK_STREAM : SOCK_SEQPACKET), + IPPROTO_SCTP); if (fd < 0) { return handleSocketError(env, errno); Thanks, -Andrew -----Original Message----- From: net-dev On Behalf Of Andrew Luo Sent: Thursday, July 26, 2018 11:31 AM To: Ivan Gerasimov ; Chris Hegarty Cc: net-dev at openjdk.java.net Subject: RE: [PATCH] SOCK_CLOEXEC for opening sockets Do we need to support compiling on a newer kernel with newer headers and then running the compiled binaries on an older platform? If so, then I think we probably have to use dlsym to call accept4 at runtime rather than compile time... Thanks, -Andrew -----Original Message----- From: net-dev On Behalf Of Ivan Gerasimov Sent: Wednesday, July 25, 2018 10:04 PM To: Chris Hegarty Cc: net-dev at openjdk.java.net Subject: Re: [PATCH] SOCK_CLOEXEC for opening sockets Hi Chris! A couple of minor comments. 1) if (s != -1 || (s == -1 && errno != EINVAL)) { This can be simplified to if (s != -1 || errno != EINVAL) { 2) What about sockets created with accept(): Shouldn't NET_Accept be modified to set O_CLOEXEC as well? On Linux accept4() can be used to pass SOCK_CLOEXEC flag. With kind regards, Ivan On 7/25/18 5:49 AM, Chris Hegarty wrote: > Alan, > >> On 25 Jul 2018, at 08:24, Alan Bateman wrote: >> >> ... >> >> As I said previously, the patch isn't complete so native code calling fork/exec may still have to deal with other file descriptors that are inherited into the child. I don't object to doing this in phases of course but somehow we have managed to get by for 20 years without this being an issue. > I added the following to the JIRA description to make this clear: > > "This JIRA issue, by itself, does not completely resolve the problem > of native code calling fork/exec, it may still have to deal with other > file descriptors that are inherited by the child. Instead this JIRA > issue is targeted at the socket and channels areas only, other areas > should be tackled on a phased approach though separate JIRA issues." > >> The updates to the various site to use the NET_* functions are fine. However, I think the new functions in net_util_md.c could be cleaner. I think it would be better to fallback to socket/socketpair + fcntl when the initial call fails with EINVAL. > Agreed. How about this ( trying to reduce the ifdef blocks, and keep > them relatively clean ) : > > --- > JNIEXPORT int JNICALL > NET_Socket(int domain, int type, int protocol) { > int s; > #if defined(SOCK_CLOEXEC) > s = socket(domain, type | SOCK_CLOEXEC, protocol); > if (s != -1 || (s == -1 && errno != EINVAL)) { > return s; > } > #endif > s = socket(domain, type, protocol); > if (s != -1) { > // Best effort - return value is intentionally ignored since the socket > // was successfully created. > fcntl(s, F_SETFD, FD_CLOEXEC); > } > return s; > } > --- > > Updated webrev: > http://cr.openjdk.java.net/~chegar/8207335/webrev.01/ > > -Chris. -- With kind regards, Ivan Gerasimov From chris.hegarty at oracle.com Tue Jul 31 19:57:39 2018 From: chris.hegarty at oracle.com (Chris Hegarty) Date: Tue, 31 Jul 2018 20:57:39 +0100 Subject: Connection timeouts in JEP 321 (HTTP Client) In-Reply-To: References: <4CA92584-6723-4887-A73D-D5741558A0A7@oracle.com> Message-ID: <445271EB-E465-420A-A8BA-6CD319F547F9@oracle.com> It is unfortunate that this has come up so late the JDK 11 lifecycle, but since this has API impact, and is the right thing to do, it is certainly worth addressing now ( rather than waiting to do something in a future release). TL;DR provide API support for setting connection and response specific timeouts, while continuing to support a single overall request timeout. The following issue has been file to track this: https://bugs.openjdk.java.net/browse/JDK-8208391 Propose ------- In the `HttpRequest.Builder` class remove the single `timeout` method and replace it with a pair of `connectTimeout` and `responseTimeout`. The `connectTimeout` method can be used to set a timeout duration that is specific to the connection phase. The `responseTimeout` method can be used to set a timeout for the actual of the HTTP response. For example, HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://foo.com/")) .connectTimeout(Duration.ofSeconds(20)) .responseTimeout(Duration.ofMinutes(1)) .header("Content-Type", "application/json") .POST(BodyPublishers.ofFile(Paths.get("file.json"))) .build(); We consider the ability to be able to set a single timeout for the overall response to be important, so the `responseTimeout` method can be used to set an overall response timeout, in the absence of a more specific `connectTimeout`. This means that the newly named `responseTimeout` is semantically equivalent to the old `timeout` when used without the new `connectTimeout`. Add a new public exception type, `HttpConnectTimeoutException` that is thrown when a connection times out. This exception type will be a subtype of the existing `HttpTimeoutException`, thus allowing for more fine grained exception handling to discern connection timeouts from response timeouts, where desired. The use of a subtype reduces the exception handling overhead for those that do not wish to take that burden, a timeout is just a timeout. Appropriate accessors will be added to `HttpRequest` to retrieve the Optional containing the connect timeout duration, and the response timeout duration. A sketch of the javadoc ( in HttpRequest.Builder ): /** * Sets the response timeout duration for this request. * *

If the response headers are not received within the specified * duration, then an {@link HttpTimeoutException} is thrown from {@link * HttpClient#send(java.net.http.HttpRequest, * java.net.http.HttpResponse.BodyHandler) HttpClient::send}, or * {@link HttpClient#sendAsync(java.net.http.HttpRequest, * java.net.http.HttpResponse.BodyHandler) HttpClient::sendAsync} * completes exceptionally with an {@code HttpTimeoutException}. * *

If a {@linkplain #connectTimeout(Duration) connect timeout duration} * has also been specified, then this timeout duration starts after the * connection has been established, and the connection setup phase is * timed separately by the connect timeout duration. If no connect * timeout duration has been specified, then this timeout duration * covers both connection setup and receiving of the response. * *

The effect of not setting a timeout duration is the same as * setting an infinite duration, ie. block forever, or the Operating * System default. * * @param duration the duration to allow the response headers to be * received * @return this builder * @throws IllegalArgumentException if the duration is non-positive */ public abstract Builder responseTimeout(Duration duration); /** * Sets the connect timeout duration for this request. * *

In the case where a new connection needs to be established, if * the connection cannot be established within the given {@code * duration}, then a {@link HttpConnectTimeoutException} is thrown * from {@link HttpClient#send(java.net.http.HttpRequest, * java.net.http.HttpResponse.BodyHandler) HttpClient::send}, or * {@link HttpClient#sendAsync(java.net.http.HttpRequest, * java.net.http.HttpResponse.BodyHandler) HttpClient::sendAsync} * completes exceptionally with a {@code HttpConnectTimeoutException}. * If a new connection does not need to be established, for example * if a connection can be reused from a previous request, then this * timeout duration has no effect. * *

The effect of not setting a connect timeout duration is defined * in the method {@link #responseTimeout(Duration) responseTimeout}. * * @param duration the duration to allow the underlying connection to be * established * @return this builder * @throws IllegalArgumentException if the duration is non-positive */ public abstract Builder connectTimeout(Duration duration); New public exception type: public class HttpConnectTimeoutException extends HttpTimeoutException { ... } To HttpRequest add: /** * Returns an {@code Optional} containing this request's response timeout * duration. If the {@linkplain Builder#responseTimeout(Duration) response * timeout duration} was not set in the request's builder, then the * {@code Optional} is empty. * * @return an {@code Optional} containing this request's response timeout * duration */ public abstract Optional responseTimeout(); /** * Returns an {@code Optional} containing this request's connect timeout * duration. If the {@linkplain Builder#connectTimeout(Duration) connect * timeout duration} was not set in the request's builder, then the * {@code Optional} is empty. * * @return an {@code Optional} containing this request's connect timeout * duration */ public abstract Optional connectTimeout(); -Chris. From simone.bordet at gmail.com Tue Jul 31 21:07:13 2018 From: simone.bordet at gmail.com (Simone Bordet) Date: Tue, 31 Jul 2018 23:07:13 +0200 Subject: Connection timeouts in JEP 321 (HTTP Client) In-Reply-To: <445271EB-E465-420A-A8BA-6CD319F547F9@oracle.com> References: <4CA92584-6723-4887-A73D-D5741558A0A7@oracle.com> <445271EB-E465-420A-A8BA-6CD319F547F9@oracle.com> Message-ID: Hi, On Tue, Jul 31, 2018 at 9:58 PM Chris Hegarty wrote: > > It is unfortunate that this has come up so late the JDK 11 lifecycle, > but since this has API impact, and is the right thing to do, it is > certainly worth addressing now ( rather than waiting to do something in > a future release). > > TL;DR provide API support for setting connection and response specific > timeouts, while continuing to support a single overall request timeout. > > The following issue has been file to track this: > https://bugs.openjdk.java.net/browse/JDK-8208391 > > Propose > ------- > > In the `HttpRequest.Builder` class remove the single `timeout` method > and replace it with a pair of `connectTimeout` and `responseTimeout`. > The `connectTimeout` method can be used to set a timeout duration that > is specific to the connection phase. The `responseTimeout` method can be > used to set a timeout for the actual of the HTTP response. For example, > > HttpRequest request = HttpRequest.newBuilder() > .uri(URI.create("https://foo.com/")) > .connectTimeout(Duration.ofSeconds(20)) > .responseTimeout(Duration.ofMinutes(1)) > .header("Content-Type", "application/json") > .POST(BodyPublishers.ofFile(Paths.get("file.json"))) > .build(); > > We consider the ability to be able to set a single timeout for the > overall response to be important, so the `responseTimeout` method can be > used to set an overall response timeout, in the absence of a more > specific `connectTimeout`. This means that the newly named > `responseTimeout` is semantically equivalent to the old `timeout` when > used without the new `connectTimeout`. I don't think this is precisely specified. AFAIU, connectTimeout is the time to perform DNS lookup plus the time to establish the TCP connection (SYN+SYN/ACK+ACK), so you may want to clarify that. But responseTimeout also is not precisely defined, and assumes that a response starts after a request, but this is not always the case. Imagine the case of uploading a huge file to the server on a slow network. The server may reply with a 500 immediately so the response side is finished almost immediately, but the request content upload may continue for minutes after the response is arrived, depending on the server implementation. The good case, where the huge upload continues normally and completes before the response is sent by the server, is difficult to quantify beforehand and therefore to configure on the request object (as it depends on the network). Point being that "responseTimeout" does not convey the fact that in certain cases 99% of the time can be spent in the request, not in the response. > /** > * Sets the response timeout duration for this request. > * > *

If the response headers are not received within the specified > * duration, then an {@link HttpTimeoutException} is thrown from {@link > * HttpClient#send(java.net.http.HttpRequest, > * java.net.http.HttpResponse.BodyHandler) HttpClient::send}, or > * {@link HttpClient#sendAsync(java.net.http.HttpRequest, > * java.net.http.HttpResponse.BodyHandler) HttpClient::sendAsync} > * completes exceptionally with an {@code HttpTimeoutException}. > * > *

If a {@linkplain #connectTimeout(Duration) connect timeout duration} > * has also been specified, then this timeout duration starts after the > * connection has been established, and the connection setup phase is > * timed separately by the connect timeout duration. If no connect > * timeout duration has been specified, then this timeout duration > * covers both connection setup and receiving of the response. > * > *

The effect of not setting a timeout duration is the same as > * setting an infinite duration, ie. block forever, or the Operating > * System default. > * > * @param duration the duration to allow the response headers to be > * received > * @return this builder > * @throws IllegalArgumentException if the duration is non-positive > */ > public abstract Builder responseTimeout(Duration duration); Again, this is not clear. If the implementation already has setup a connection (because it pools them, or in the HTTP/2 case), it is not clear when this responseTimeout starts. Does it start _after_ the whole request has been sent? Does it start as soon as the request is sent? If the goal is to limit the total request+response time (and by experience it is what generally people want), then I think the name "timeout" as it was before is a better choice and needs to be defined as request+response timeout. It should also be clarified what happens in case of conversations such as redirects or authentication challenges: it is the whole conversation subject to the timeout, or single request+response pairs? > /** > * Sets the connect timeout duration for this request. > * > *

In the case where a new connection needs to be established, if > * the connection cannot be established within the given {@code > * duration}, then a {@link HttpConnectTimeoutException} is thrown > * from {@link HttpClient#send(java.net.http.HttpRequest, > * java.net.http.HttpResponse.BodyHandler) HttpClient::send}, or > * {@link HttpClient#sendAsync(java.net.http.HttpRequest, > * java.net.http.HttpResponse.BodyHandler) HttpClient::sendAsync} > * completes exceptionally with a {@code HttpConnectTimeoutException}. > * If a new connection does not need to be established, for example > * if a connection can be reused from a previous request, then this > * timeout duration has no effect. > * > *

The effect of not setting a connect timeout duration is defined > * in the method {@link #responseTimeout(Duration) responseTimeout}. > * > * @param duration the duration to allow the underlying connection to be > * established > * @return this builder > * @throws IllegalArgumentException if the duration is non-positive > */ > public abstract Builder connectTimeout(Duration duration); Why this is on the request builder and not in the HttpClient builder? The connectTimeout is not a request property, it is a HttpClient property as it is HttpClient that opens (to pool them) connections, and this is even more true for HTTP/2 where apart the first request possibly no other connections are opened towards the same origin. Imagine in the future you want to add a functionality that pre-opens connections to specified origins to reduce the latency when sending requests, similar to ThreadPoolExecutor.prestartAllCoreThreads(). I would argue that you would put this method in HttpClient and so it is HttpClient that needs to be configured with the connectTimeout. I propose to keep "timeout" as a total request+response timeout (and possibly conversation timeout, your call) on the request builder, and to move "connectTimeout" to the HttpClient builder, specifying that it means DNS lookup plus TCP connection establishment. In case a request needs to open a connection, "timeout" will still be the total time from when the request is sent to when both request and response are finished, including the connectTimeout. By having a typically shorter connectTimeout (say 5 seconds) and a longer total timeout (say 2 minutes), a request will fail in 5 seconds if HttpClient fails to open a connection to the origin server, and fail in 2 minutes if it takes too much. Finally, I would consider TLS handshake time as part of the request data: the cost will be paid by the first request and capped by "total" timeout (not connectTimeout). With TLS 1.3 optimizations, it may be just few TLS bytes before the encrypted request bytes. Thanks! -- Simone Bordet --- Finally, no matter how good the architecture and design are, to deliver bug-free software with optimal performance and reliability, the implementation technique must be flawless. Victoria Livschitz