From 769ef151311a69186026aa8ed05a235229adaec1 Mon Sep 17 00:00:00 2001 From: Jakub Kulik Date: Tue, 1 Sep 2020 15:56:00 +0200 Subject: [PATCH 1/4] bpo-41687: Fix sendfile implementation on Solaris --- Lib/test/test_asyncio/test_sendfile.py | 2 ++ Modules/posixmodule.c | 17 +++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/Lib/test/test_asyncio/test_sendfile.py b/Lib/test/test_asyncio/test_sendfile.py index a30d9b9b4d9a01..726819f1ee0bb1 100644 --- a/Lib/test/test_asyncio/test_sendfile.py +++ b/Lib/test/test_asyncio/test_sendfile.py @@ -446,6 +446,8 @@ def test_sendfile_ssl_close_peer_after_receiving(self): self.assertEqual(srv_proto.data, self.DATA) self.assertEqual(self.file.tell(), len(self.DATA)) + @unittest.skipIf(sys.platform.startswith('sunos'), + "Doesn't work on Solaris") def test_sendfile_close_peer_in_the_middle_of_receiving(self): srv_proto, cli_proto = self.prepare_sendfile(close_after=1024) with self.assertRaises(ConnectionError): diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index a6a4b9f012f009..9980aac3c60899 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -9518,6 +9518,23 @@ os_sendfile_impl(PyObject *module, int out_fd, int in_fd, PyObject *offobj, if (!Py_off_t_converter(offobj, &offset)) return NULL; +#if defined(__sun) && defined(__SVR4) + int res; + struct stat st; + + do { + Py_BEGIN_ALLOW_THREADS + res = fstat(in_fd, &st); + Py_END_ALLOW_THREADS + } while (res != 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); + if (ret < 0) + return (!async_err) ? posix_error() : NULL; + + if (offset >= st.st_size) { + return Py_BuildValue("i", 0); + } +#endif + do { Py_BEGIN_ALLOW_THREADS ret = sendfile(out_fd, in_fd, &offset, count); From 5c126fe6711de8f8dc9624745c00251356d2bd57 Mon Sep 17 00:00:00 2001 From: Jakub Kulik Date: Tue, 1 Sep 2020 15:58:26 +0200 Subject: [PATCH 2/4] add news entry --- .../NEWS.d/next/Library/2020-09-01-15-57-51.bpo-41687.m1b1KA.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2020-09-01-15-57-51.bpo-41687.m1b1KA.rst diff --git a/Misc/NEWS.d/next/Library/2020-09-01-15-57-51.bpo-41687.m1b1KA.rst b/Misc/NEWS.d/next/Library/2020-09-01-15-57-51.bpo-41687.m1b1KA.rst new file mode 100644 index 00000000000000..284f500735701e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-09-01-15-57-51.bpo-41687.m1b1KA.rst @@ -0,0 +1 @@ +Fix implementation of sendfile to be compatible with Solaris. From 94cbb652e0e62d5698f04a1384e5339dc410d14e Mon Sep 17 00:00:00 2001 From: Jakub Kulik Date: Wed, 2 Sep 2020 07:19:04 +0200 Subject: [PATCH 3/4] Add comment summarizing the issue --- Modules/posixmodule.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 9980aac3c60899..00ba7580302bba 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -9519,6 +9519,8 @@ os_sendfile_impl(PyObject *module, int out_fd, int in_fd, PyObject *offobj, return NULL; #if defined(__sun) && defined(__SVR4) + // On Solaris, sendfile raises EINVAL rather than returning 0 + // when the offset is equal or bigger than the in_fd size. int res; struct stat st; From bfbdcbb2e4047de2494328cf292d765bf392cbcf Mon Sep 17 00:00:00 2001 From: Jakub Kulik Date: Sat, 5 Sep 2020 08:25:17 +0200 Subject: [PATCH 4/4] Added test skip explanation --- Lib/test/test_asyncio/test_sendfile.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Lib/test/test_asyncio/test_sendfile.py b/Lib/test/test_asyncio/test_sendfile.py index 726819f1ee0bb1..01c698653ec67e 100644 --- a/Lib/test/test_asyncio/test_sendfile.py +++ b/Lib/test/test_asyncio/test_sendfile.py @@ -446,6 +446,10 @@ def test_sendfile_ssl_close_peer_after_receiving(self): self.assertEqual(srv_proto.data, self.DATA) self.assertEqual(self.file.tell(), len(self.DATA)) + # On Solaris, lowering SO_RCVBUF on a TCP connection after it has been + # established has no effect. Due to its age, this bug affects both Oracle + # Solaris as well as all other OpenSolaris forks (unless they fixed it + # themselves). @unittest.skipIf(sys.platform.startswith('sunos'), "Doesn't work on Solaris") def test_sendfile_close_peer_in_the_middle_of_receiving(self):