Sendfile on Solaris can raise EINVAL if offset is bigger than size of the file. Because this would not send any data anyway, we can safely avoid calling this function at all. The test skip is necessary due to a long-standing bug 14925973, due to which lowering SO_RCVBUF on a TCP connection after it has been established has no effect. This patch was accepted upstream and will be part of Python 3.9 and later: https://bugs.python.org/issue41687 --- Python-3.7.8/Modules/posixmodule.c +++ Python-3.7.8/Modules/posixmodule.c @@ -8399,6 +8399,10 @@ posix_sendfile(PyObject *self, PyObject int async_err = 0; off_t offset; +#if defined(__sun) && defined(__SVR4) + struct stat st; +#endif + #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__APPLE__) #ifndef __APPLE__ Py_ssize_t len; @@ -8545,6 +8549,23 @@ done: if (!Py_off_t_converter(offobj, &offset)) 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. + do { + Py_BEGIN_ALLOW_THREADS + ret = fstat(in, &st); + Py_END_ALLOW_THREADS + } while (ret != 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); + if (ret < 0) + return (!async_err) ? posix_error() : NULL; + + // sendfile on Solaris doesn't accept offset bigger than the in size + if (offset >= st.st_size) { + return Py_BuildValue("i", 0); + } +#endif + do { Py_BEGIN_ALLOW_THREADS ret = sendfile(out, in, &offset, count); --- Python-3.7.8/Lib/test/test_asyncio/test_events.py +++ Python-3.7.8/Lib/test/test_asyncio/test_events.py @@ -2498,6 +2498,12 @@ class SendfileMixin(SendfileBase): 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): srv_proto, cli_proto = self.prepare_sendfile(close_after=1024) with self.assertRaises(ConnectionError):