From 13029fb524f292be57380865572c8fda6ea6eab5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnter=20Obiltschnig?= Date: Fri, 7 Feb 2025 18:06:14 +0100 Subject: [PATCH 1/8] fix(Net): fix SocketImpl::sendFile() #4831 --- Net/include/Poco/Net/SocketImpl.h | 36 +++++--- Net/include/Poco/Net/StreamSocket.h | 18 ++-- Net/src/HTTPServerResponseImpl.cpp | 4 +- Net/src/SocketImpl.cpp | 126 ++++++++++++++++++++-------- Net/src/StreamSocket.cpp | 8 +- 5 files changed, 137 insertions(+), 55 deletions(-) diff --git a/Net/include/Poco/Net/SocketImpl.h b/Net/include/Poco/Net/SocketImpl.h index a2d4c8e620..62170ddfda 100644 --- a/Net/include/Poco/Net/SocketImpl.h +++ b/Net/include/Poco/Net/SocketImpl.h @@ -287,6 +287,22 @@ class Net_API SocketImpl: public Poco::RefCountedObject /// The preferred way for a socket to receive urgent data /// is by enabling the SO_OOBINLINE option. + virtual std::streamsize sendFile(Poco::FileInputStream& FileInputStream, std::streamoff offset = 0); + /// Sends the contents of a file in an optimized way, if possible. + /// + /// On POSIX systems, this means using sendfile() or sendfile64(). + /// On Windows, this means using TransmitFile(). + /// + /// If neither is available, or the socket is a SecureSocketImpl() + /// (secure() returns true), falls back to reading the file + /// block by block and callind sendBytes(). + /// + /// Returns the number of bytes sent, which may be + /// less than the number of bytes specified. + /// + /// Throws NetException (or a subclass) in case of any errors. + /// Also throws if the socket is non-blocking. + virtual int available(); /// Returns the number of bytes available that can be read /// without causing the socket to block. @@ -487,17 +503,7 @@ class Net_API SocketImpl: public Poco::RefCountedObject bool initialized() const; /// Returns true iff the underlying socket is initialized. -#ifdef POCO_HAVE_SENDFILE - Int64 sendFile(FileInputStream &FileInputStream, UInt64 offset = 0); - /// Sends file using system function - /// for posix systems - with sendfile[64](...) - /// for windows - with TransmitFile(...) - /// - /// Returns the number of bytes sent, which may be - /// less than the number of bytes specified. - /// - /// Throws NetException (or a subclass) in case of any errors. -#endif + protected: SocketImpl(); /// Creates a SocketImpl. @@ -538,6 +544,14 @@ class Net_API SocketImpl: public Poco::RefCountedObject void checkBrokenTimeout(SelectMode mode); + std::streamsize sendFileNative(Poco::FileInputStream& FileInputStream, std::streamoff offset); + /// Implements sendFile() using an OS-specific API like + /// sendfile() or TransmitFile(). + + std::streamsize sendFileBlockwise(Poco::FileInputStream& FileInputStream, std::streamoff offset); + /// Implements sendFile() by reading the file blockwise and + /// calling sendBytes() for each block. + static int lastError(); /// Returns the last error code. diff --git a/Net/include/Poco/Net/StreamSocket.h b/Net/include/Poco/Net/StreamSocket.h index fa5706316d..7b007f352b 100644 --- a/Net/include/Poco/Net/StreamSocket.h +++ b/Net/include/Poco/Net/StreamSocket.h @@ -267,17 +267,23 @@ class Net_API StreamSocket: public Socket /// /// The preferred way for a socket to receive urgent data /// is by enabling the SO_OOBINLINE option. -#ifdef POCO_HAVE_SENDFILE - IntPtr sendFile(FileInputStream &FileInputStream, UIntPtr offset = 0); - /// Sends file using system function - /// for posix systems - with sendfile[64](...) - /// for windows - with TransmitFile(...) + + std::streamsize sendFile(Poco::FileInputStream& FileInputStream, std::streamoff offset = 0); + /// Sends the contents of a file in an optimized way, if possible. + /// + /// On POSIX systems, this means using sendfile() or sendfile64(). + /// On Windows, this means using TransmitFile(). + /// + /// If neither is available, or the socket is a SecureSocketImpl() + /// (secure() returns true), falls back to reading the file + /// block by block and callind sendBytes(). /// /// Returns the number of bytes sent, which may be /// less than the number of bytes specified. /// /// Throws NetException (or a subclass) in case of any errors. -#endif + /// Also throws if the socket is non-blocking. + StreamSocket(SocketImpl* pImpl); /// Creates the Socket and attaches the given SocketImpl. /// The socket takes ownership of the SocketImpl. diff --git a/Net/src/HTTPServerResponseImpl.cpp b/Net/src/HTTPServerResponseImpl.cpp index ce4fd5bf36..d1d4dc1a01 100644 --- a/Net/src/HTTPServerResponseImpl.cpp +++ b/Net/src/HTTPServerResponseImpl.cpp @@ -135,8 +135,8 @@ void HTTPServerResponseImpl::sendFile(const std::string& path, const std::string #ifdef POCO_HAVE_SENDFILE _pStream->flush(); // flush the HTTP headers to the socket, required by HTTP 1.0 and above - Poco::IntPtr sent = 0; - Poco::IntPtr offset = 0; + std::streamsize sent = 0; + std::streamoff offset = 0; while (sent < length) { offset = sent; diff --git a/Net/src/SocketImpl.cpp b/Net/src/SocketImpl.cpp index b0c828fb3f..c79757999c 100644 --- a/Net/src/SocketImpl.cpp +++ b/Net/src/SocketImpl.cpp @@ -696,6 +696,27 @@ void SocketImpl::sendUrgent(unsigned char data) } + + +std::streamsize SocketImpl::sendFile(FileInputStream& fileInputStream, std::streamoff offset) +{ + if (!getBlocking()) throw NetException("sendFile() not supported for non-blocking sockets"); + +#ifdef POCO_HAVE_SENDFILE + if (secure()) + { + return sendFileBlockwise(fileInputStream, offset); + } + else + { + return sendFileNative(fileInputStream, offset); + } +#else + return sendFileBlockwise(fileInputStream, offset); +#endif +} + + int SocketImpl::available() { int result = 0; @@ -1424,9 +1445,13 @@ void SocketImpl::error(int code, const std::string& arg) throw IOException(NumberFormatter::format(code), arg, code); } } + + #ifdef POCO_HAVE_SENDFILE #ifdef POCO_OS_FAMILY_WINDOWS -Poco::Int64 SocketImpl::sendFile(FileInputStream &fileInputStream, Poco::UInt64 offset) + + +std::streamsize SocketImpl::sendFileNative(FileInputStream& fileInputStream, std::streamoff offset) { FileIOS::NativeHandle fd = fileInputStream.nativeHandle(); UInt64 fileSize = fileInputStream.size(); @@ -1441,52 +1466,61 @@ Poco::Int64 SocketImpl::sendFile(FileInputStream &fileInputStream, Poco::UInt64 if (overlapped.hEvent == nullptr) { int err = GetLastError(); - error(err, std::string("[sendfile error]") + Error::getMessage(err)); + error(err); } bool result = TransmitFile(_sockfd, fd, sentSize, 0, &overlapped, nullptr, 0); if (!result) { int err = WSAGetLastError(); - if ((err != ERROR_IO_PENDING) && (WSAGetLastError() != WSA_IO_PENDING)) { + if ((err != ERROR_IO_PENDING) && (WSAGetLastError() != WSA_IO_PENDING)) + { CloseHandle(overlapped.hEvent); - error(err, std::string("[sendfile error]") + Error::getMessage(err)); + error(err); } WaitForSingleObject(overlapped.hEvent, INFINITE); } CloseHandle(overlapped.hEvent); return sentSize; } + + #else -Int64 _sendfile(poco_socket_t sd, FileIOS::NativeHandle fd, UInt64 offset, std::streamoff sentSize) + + +namespace { - Int64 sent = 0; -#ifdef __USE_LARGEFILE64 - sent = sendfile64(sd, fd, (off64_t *)&offset, sentSize); -#else -#if POCO_OS == POCO_OS_LINUX && !defined(POCO_EMSCRIPTEN) - sent = sendfile(sd, fd, (off_t *)&offset, sentSize); -#elif POCO_OS == POCO_OS_MAC_OS_X - int result = sendfile(fd, sd, offset, &sentSize, nullptr, 0); - if (result < 0) - { - sent = -1; - } - else - { - sent = sentSize; - } -#else - throw Poco::NotImplementedException("sendfile not implemented for this platform"); -#endif -#endif - if (errno == EAGAIN || errno == EWOULDBLOCK) + std::streamsize sendFilePosix(poco_socket_t sd, FileIOS::NativeHandle fd, std::streamsize offset, std::streamoff sentSize) { - sent = 0; - } - return sent; + Int64 sent = 0; + #ifdef __USE_LARGEFILE64 + sent = sendfile64(sd, fd, (off64_t*) &offset, sentSize); + #else + #if POCO_OS == POCO_OS_LINUX && !defined(POCO_EMSCRIPTEN) + sent = sendfile(sd, fd, (off_t*) &offset, sentSize); + #elif POCO_OS == POCO_OS_MAC_OS_X + int result = sendfile(fd, sd, offset, &sentSize, nullptr, 0); + if (result < 0) + { + sent = -1; + } + else + { + sent = sentSize; + } + #else + throw Poco::NotImplementedException("sendfile not implemented for this platform"); + #endif + #endif + if (errno == EAGAIN || errno == EWOULDBLOCK) + { + sent = 0; + } + return sent; + } } -Int64 SocketImpl::sendFile(FileInputStream &fileInputStream, UInt64 offset) + +std::streamsize SocketImpl::sendFileNative(FileInputStream& fileInputStream, std::streamoff offset) { FileIOS::NativeHandle fd = fileInputStream.nativeHandle(); UInt64 fileSize = fileInputStream.size(); @@ -1500,20 +1534,46 @@ Int64 SocketImpl::sendFile(FileInputStream &fileInputStream, UInt64 offset) while (sent == 0) { errno = 0; - sent = _sendfile(_sockfd, fd, offset, sentSize); + sent = sendFilePosix(_sockfd, fd, offset, sentSize); if (sent < 0) { - error(errno, std::string("[sendfile error]") + Error::getMessage(errno)); + error(errno); } } - if(old_sa.sa_handler == SIG_ERR) + if (old_sa.sa_handler == SIG_ERR) { old_sa.sa_handler = SIG_DFL; } sigaction(SIGPIPE, &old_sa, nullptr); return sent; } + + #endif // POCO_OS_FAMILY_WINDOWS #endif // POCO_HAVE_SENDFILE + +std::streamsize SocketImpl::sendFileBlockwise(FileInputStream& fileInputStream, std::streamoff offset) +{ + fileInputStream.seekg(offset); + Poco::Buffer buffer(8192); + + std::streamsize len = 0; + fileInputStream.read(buffer.begin(), buffer.size()); + std::streamsize n = fileInputStream.gcount(); + while (n > 0) + { + len += n; + sendBytes(buffer.begin(), n); + if (fileInputStream) + { + fileInputStream.read(buffer.begin(), buffer.size()); + n = fileInputStream.gcount(); + } + else n = 0; + } + return len; +} + + } } // namespace Poco::Net diff --git a/Net/src/StreamSocket.cpp b/Net/src/StreamSocket.cpp index dc8e848583..20023ed8a4 100644 --- a/Net/src/StreamSocket.cpp +++ b/Net/src/StreamSocket.cpp @@ -212,10 +212,12 @@ void StreamSocket::sendUrgent(unsigned char data) { impl()->sendUrgent(data); } -#ifdef POCO_HAVE_SENDFILE -IntPtr StreamSocket::sendFile(FileInputStream &fileInputStream, UIntPtr offset) + + +std::streamsize StreamSocket::sendFile(Poco::FileInputStream& fileInputStream, std::streamoff offset) { return impl()->sendFile(fileInputStream, offset); } -#endif + + } } // namespace Poco::Net From 6fb0debd71912c6292c1e5c30fbfaeeb100b2128 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnter=20Obiltschnig?= Date: Fri, 7 Feb 2025 18:42:17 +0100 Subject: [PATCH 2/8] chore: add test for sendFile() --- Net/testsuite/src/SocketTest.cpp | 43 +++++++++++++++++ Net/testsuite/src/SocketTest.h | 2 + .../testsuite/src/SecureStreamSocketTest.cpp | 47 +++++++++++++++++++ .../testsuite/src/SecureStreamSocketTest.h | 1 + 4 files changed, 93 insertions(+) diff --git a/Net/testsuite/src/SocketTest.cpp b/Net/testsuite/src/SocketTest.cpp index b45bd3dde4..e9b41a0544 100644 --- a/Net/testsuite/src/SocketTest.cpp +++ b/Net/testsuite/src/SocketTest.cpp @@ -22,6 +22,8 @@ #include "Poco/FIFOBuffer.h" #include "Poco/Delegate.h" #include "Poco/File.h" +#include "Poco/TemporaryFile.h" +#include "Poco/FileStream.h" #include "Poco/Path.h" #include @@ -667,6 +669,46 @@ void SocketTest::testUseFd() } +void SocketTest::testSendFile() +{ + EchoServer echoServer; + StreamSocket ss; + ss.connect(SocketAddress("127.0.0.1", echoServer.port())); + + std::string sentData = "Hello, world!"; + + Poco::TemporaryFile file; + Poco::FileOutputStream ostr(file.path()); + ostr.write(sentData.data(), sentData.size()); + ostr.close(); + + Poco::FileInputStream istr(file.path()); + std::streamsize sent = 0; + std::streamoff off = 0; + while (sent < file.getSize()) + { + sent += ss.sendFile(istr, sent); + } + istr.close(); + + std::string receivedData; + char buffer[1024]; + int n = ss.receiveBytes(buffer, sizeof(buffer)); + while (n > 0) + { + receivedData.append(buffer, n); + if (receivedData.size() < sentData.size()) + n = ss.receiveBytes(buffer, sizeof(buffer)); + else + n = 0; + } + + assertTrue (receivedData == sentData); + + ss.close(); +} + + void SocketTest::onReadable(bool& b) { if (b) ++_notToReadable; @@ -724,6 +766,7 @@ CppUnit::Test* SocketTest::suite() CppUnit_addTest(pSuite, SocketTest, testEchoUnixLocal); CppUnit_addTest(pSuite, SocketTest, testUnixLocalAbstract); CppUnit_addTest(pSuite, SocketTest, testUseFd); + CppUnit_addTest(pSuite, SocketTest, testSendFile); return pSuite; } diff --git a/Net/testsuite/src/SocketTest.h b/Net/testsuite/src/SocketTest.h index 2bfe8526b5..af026e7d8c 100644 --- a/Net/testsuite/src/SocketTest.h +++ b/Net/testsuite/src/SocketTest.h @@ -45,9 +45,11 @@ class SocketTest: public CppUnit::TestCase void testSelect2(); void testSelect3(); #endif + void testEchoUnixLocal(); void testUnixLocalAbstract(); void testUseFd(); + void testSendFile(); void setUp() override; void tearDown() override; diff --git a/NetSSL_OpenSSL/testsuite/src/SecureStreamSocketTest.cpp b/NetSSL_OpenSSL/testsuite/src/SecureStreamSocketTest.cpp index 10935c5a54..ecb057876e 100644 --- a/NetSSL_OpenSSL/testsuite/src/SecureStreamSocketTest.cpp +++ b/NetSSL_OpenSSL/testsuite/src/SecureStreamSocketTest.cpp @@ -25,6 +25,9 @@ #include "Poco/Util/Application.h" #include "Poco/Util/AbstractConfiguration.h" #include "Poco/Thread.h" +#include "Poco/File.h" +#include "Poco/TemporaryFile.h" +#include "Poco/FileStream.h" #include @@ -200,6 +203,49 @@ void SecureStreamSocketTest::testNB() } +void SecureStreamSocketTest::testSendFile() +{ + SecureServerSocket svs(0); + TCPServer srv(new TCPServerConnectionFactoryImpl(), svs); + srv.start(); + + SecureStreamSocket ss; + ss.connect(SocketAddress("127.0.0.1", srv.port())); + + std::string sentData = "Hello, world!"; + + Poco::TemporaryFile file; + Poco::FileOutputStream ostr(file.path()); + ostr.write(sentData.data(), sentData.size()); + ostr.close(); + + Poco::FileInputStream istr(file.path()); + std::streamsize sent = 0; + std::streamoff off = 0; + while (sent < file.getSize()) + { + sent += ss.sendFile(istr, sent); + } + istr.close(); + + std::string receivedData; + char buffer[1024]; + int n = ss.receiveBytes(buffer, sizeof(buffer)); + while (n > 0) + { + receivedData.append(buffer, n); + if (receivedData.size() < sentData.size()) + n = ss.receiveBytes(buffer, sizeof(buffer)); + else + n = 0; + } + + assertTrue (receivedData == sentData); + + ss.close(); +} + + void SecureStreamSocketTest::setUp() { } @@ -217,6 +263,7 @@ CppUnit::Test* SecureStreamSocketTest::suite() CppUnit_addTest(pSuite, SecureStreamSocketTest, testSendReceive); CppUnit_addTest(pSuite, SecureStreamSocketTest, testPeek); CppUnit_addTest(pSuite, SecureStreamSocketTest, testNB); + CppUnit_addTest(pSuite, SecureStreamSocketTest, testSendFile); return pSuite; } diff --git a/NetSSL_OpenSSL/testsuite/src/SecureStreamSocketTest.h b/NetSSL_OpenSSL/testsuite/src/SecureStreamSocketTest.h index 62ac9e1c7a..f072e90fc3 100644 --- a/NetSSL_OpenSSL/testsuite/src/SecureStreamSocketTest.h +++ b/NetSSL_OpenSSL/testsuite/src/SecureStreamSocketTest.h @@ -27,6 +27,7 @@ class SecureStreamSocketTest: public CppUnit::TestCase void testSendReceive(); void testPeek(); void testNB(); + void testSendFile(); void setUp(); void tearDown(); From 3d8040bb172d62379beb49b040f4aec4a8e7f2c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnter=20Obiltschnig?= Date: Fri, 7 Feb 2025 20:43:28 +0100 Subject: [PATCH 3/8] fix(tests): remove unused variables --- Net/testsuite/src/SocketTest.cpp | 1 - NetSSL_OpenSSL/testsuite/src/SecureStreamSocketTest.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/Net/testsuite/src/SocketTest.cpp b/Net/testsuite/src/SocketTest.cpp index e9b41a0544..52b0763343 100644 --- a/Net/testsuite/src/SocketTest.cpp +++ b/Net/testsuite/src/SocketTest.cpp @@ -684,7 +684,6 @@ void SocketTest::testSendFile() Poco::FileInputStream istr(file.path()); std::streamsize sent = 0; - std::streamoff off = 0; while (sent < file.getSize()) { sent += ss.sendFile(istr, sent); diff --git a/NetSSL_OpenSSL/testsuite/src/SecureStreamSocketTest.cpp b/NetSSL_OpenSSL/testsuite/src/SecureStreamSocketTest.cpp index ecb057876e..dd04d621e2 100644 --- a/NetSSL_OpenSSL/testsuite/src/SecureStreamSocketTest.cpp +++ b/NetSSL_OpenSSL/testsuite/src/SecureStreamSocketTest.cpp @@ -221,7 +221,6 @@ void SecureStreamSocketTest::testSendFile() Poco::FileInputStream istr(file.path()); std::streamsize sent = 0; - std::streamoff off = 0; while (sent < file.getSize()) { sent += ss.sendFile(istr, sent); From 66c1d30bb4dab0b9c3c5258d7409dc94eb8b7382 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnter=20Obiltschnig?= Date: Sat, 8 Feb 2025 12:57:24 +0100 Subject: [PATCH 4/8] enh(Net): StreamSocket::sendFile() takes additional count parameter --- Net/include/Poco/Net/SocketImpl.h | 9 +- Net/include/Poco/Net/StreamSocket.h | 5 +- Net/src/SocketImpl.cpp | 63 +++++--- Net/src/StreamSocket.cpp | 4 +- Net/testsuite/src/SocketTest.cpp | 146 ++++++++++++++++-- Net/testsuite/src/SocketTest.h | 2 + .../testsuite/src/SecureStreamSocketTest.cpp | 133 ++++++++++++++-- .../testsuite/src/SecureStreamSocketTest.h | 2 + 8 files changed, 305 insertions(+), 59 deletions(-) diff --git a/Net/include/Poco/Net/SocketImpl.h b/Net/include/Poco/Net/SocketImpl.h index 62170ddfda..4537f1965a 100644 --- a/Net/include/Poco/Net/SocketImpl.h +++ b/Net/include/Poco/Net/SocketImpl.h @@ -287,9 +287,12 @@ class Net_API SocketImpl: public Poco::RefCountedObject /// The preferred way for a socket to receive urgent data /// is by enabling the SO_OOBINLINE option. - virtual std::streamsize sendFile(Poco::FileInputStream& FileInputStream, std::streamoff offset = 0); + virtual std::streamsize sendFile(Poco::FileInputStream& FileInputStream, std::streamoff offset = 0, std::streamsize count = 0); /// Sends the contents of a file in an optimized way, if possible. /// + /// If count is != 0, sends the given number of bytes, otherwise + /// sends all bytes, starting from the given offset. + /// /// On POSIX systems, this means using sendfile() or sendfile64(). /// On Windows, this means using TransmitFile(). /// @@ -544,11 +547,11 @@ class Net_API SocketImpl: public Poco::RefCountedObject void checkBrokenTimeout(SelectMode mode); - std::streamsize sendFileNative(Poco::FileInputStream& FileInputStream, std::streamoff offset); + std::streamsize sendFileNative(Poco::FileInputStream& FileInputStream, std::streamoff offset, std::streamsize count); /// Implements sendFile() using an OS-specific API like /// sendfile() or TransmitFile(). - std::streamsize sendFileBlockwise(Poco::FileInputStream& FileInputStream, std::streamoff offset); + std::streamsize sendFileBlockwise(Poco::FileInputStream& FileInputStream, std::streamoff offset, std::streamsize count); /// Implements sendFile() by reading the file blockwise and /// calling sendBytes() for each block. diff --git a/Net/include/Poco/Net/StreamSocket.h b/Net/include/Poco/Net/StreamSocket.h index 7b007f352b..e81c25a4d8 100644 --- a/Net/include/Poco/Net/StreamSocket.h +++ b/Net/include/Poco/Net/StreamSocket.h @@ -268,9 +268,12 @@ class Net_API StreamSocket: public Socket /// The preferred way for a socket to receive urgent data /// is by enabling the SO_OOBINLINE option. - std::streamsize sendFile(Poco::FileInputStream& FileInputStream, std::streamoff offset = 0); + std::streamsize sendFile(Poco::FileInputStream& FileInputStream, std::streamoff offset = 0, std::streamsize count = 0); /// Sends the contents of a file in an optimized way, if possible. /// + /// If count is != 0, sends the given number of bytes, otherwise + /// sends all bytes, starting from the given offset. + /// /// On POSIX systems, this means using sendfile() or sendfile64(). /// On Windows, this means using TransmitFile(). /// diff --git a/Net/src/SocketImpl.cpp b/Net/src/SocketImpl.cpp index c79757999c..055ffcee7e 100644 --- a/Net/src/SocketImpl.cpp +++ b/Net/src/SocketImpl.cpp @@ -698,21 +698,21 @@ void SocketImpl::sendUrgent(unsigned char data) -std::streamsize SocketImpl::sendFile(FileInputStream& fileInputStream, std::streamoff offset) +std::streamsize SocketImpl::sendFile(FileInputStream& fileInputStream, std::streamoff offset, std::streamsize count) { if (!getBlocking()) throw NetException("sendFile() not supported for non-blocking sockets"); #ifdef POCO_HAVE_SENDFILE if (secure()) { - return sendFileBlockwise(fileInputStream, offset); + return sendFileBlockwise(fileInputStream, offset, count); } else { - return sendFileNative(fileInputStream, offset); + return sendFileNative(fileInputStream, offset, count); } #else - return sendFileBlockwise(fileInputStream, offset); + return sendFileBlockwise(fileInputStream, offset, count); #endif } @@ -1451,11 +1451,10 @@ void SocketImpl::error(int code, const std::string& arg) #ifdef POCO_OS_FAMILY_WINDOWS -std::streamsize SocketImpl::sendFileNative(FileInputStream& fileInputStream, std::streamoff offset) +std::streamsize SocketImpl::sendFileNative(FileInputStream& fileInputStream, std::streamoff offset, std::streamsize count) { FileIOS::NativeHandle fd = fileInputStream.nativeHandle(); - UInt64 fileSize = fileInputStream.size(); - std::streamoff sentSize = fileSize - offset; + if (count == 0) count = fileInputStream.size() - offset; LARGE_INTEGER offsetHelper; offsetHelper.QuadPart = offset; OVERLAPPED overlapped; @@ -1468,7 +1467,7 @@ std::streamsize SocketImpl::sendFileNative(FileInputStream& fileInputStream, std int err = GetLastError(); error(err); } - bool result = TransmitFile(_sockfd, fd, sentSize, 0, &overlapped, nullptr, 0); + bool result = TransmitFile(_sockfd, fd, count, 0, &overlapped, nullptr, 0); if (!result) { int err = WSAGetLastError(); @@ -1480,7 +1479,7 @@ std::streamsize SocketImpl::sendFileNative(FileInputStream& fileInputStream, std WaitForSingleObject(overlapped.hEvent, INFINITE); } CloseHandle(overlapped.hEvent); - return sentSize; + return count; } @@ -1489,23 +1488,33 @@ std::streamsize SocketImpl::sendFileNative(FileInputStream& fileInputStream, std namespace { - std::streamsize sendFilePosix(poco_socket_t sd, FileIOS::NativeHandle fd, std::streamsize offset, std::streamoff sentSize) + std::streamsize sendFileUnix(poco_socket_t sd, FileIOS::NativeHandle fd, std::streamsize offset, std::streamoff count) { Int64 sent = 0; #ifdef __USE_LARGEFILE64 - sent = sendfile64(sd, fd, (off64_t*) &offset, sentSize); + sent = sendfile64(sd, fd, (off64_t*) &offset, count); #else #if POCO_OS == POCO_OS_LINUX && !defined(POCO_EMSCRIPTEN) - sent = sendfile(sd, fd, (off_t*) &offset, sentSize); + sent = sendfile(sd, fd, (off_t*) &offset, count); #elif POCO_OS == POCO_OS_MAC_OS_X - int result = sendfile(fd, sd, offset, &sentSize, nullptr, 0); + int result = sendfile(fd, sd, offset, &count, NULL, 0); if (result < 0) { sent = -1; } else { - sent = sentSize; + sent = count; + } + #elif POCO_OS == POCO_OS_FREE_BSD + int result = sendfile(fd, sd, offset, &count, NULL, NULL, 0); + if (result < 0) + { + sent = -1; + } + else + { + sent = count; } #else throw Poco::NotImplementedException("sendfile not implemented for this platform"); @@ -1520,12 +1529,11 @@ namespace } -std::streamsize SocketImpl::sendFileNative(FileInputStream& fileInputStream, std::streamoff offset) +std::streamsize SocketImpl::sendFileNative(FileInputStream& fileInputStream, std::streamoff offset, std::streamsize count) { FileIOS::NativeHandle fd = fileInputStream.nativeHandle(); - UInt64 fileSize = fileInputStream.size(); - std::streamoff sentSize = fileSize - offset; - Int64 sent = 0; + if (count == 0) count = fileInputStream.size() - offset; + std::streamsize sent = 0; struct sigaction sa, old_sa; sa.sa_handler = SIG_IGN; sigemptyset(&sa.sa_mask); @@ -1534,7 +1542,7 @@ std::streamsize SocketImpl::sendFileNative(FileInputStream& fileInputStream, std while (sent == 0) { errno = 0; - sent = sendFilePosix(_sockfd, fd, offset, sentSize); + sent = sendFileUnix(_sockfd, fd, offset, count); if (sent < 0) { error(errno); @@ -1553,21 +1561,28 @@ std::streamsize SocketImpl::sendFileNative(FileInputStream& fileInputStream, std #endif // POCO_HAVE_SENDFILE -std::streamsize SocketImpl::sendFileBlockwise(FileInputStream& fileInputStream, std::streamoff offset) +std::streamsize SocketImpl::sendFileBlockwise(FileInputStream& fileInputStream, std::streamoff offset, std::streamsize count) { - fileInputStream.seekg(offset); + fileInputStream.seekg(offset, std::ios_base::beg); Poco::Buffer buffer(8192); + std::size_t bufferSize = buffer.size(); + if (count > 0 && bufferSize > count) bufferSize = count; std::streamsize len = 0; - fileInputStream.read(buffer.begin(), buffer.size()); + fileInputStream.read(buffer.begin(), bufferSize); std::streamsize n = fileInputStream.gcount(); - while (n > 0) + while (n > 0 && (count == 0 || len < count)) { len += n; sendBytes(buffer.begin(), n); + if (count > 0 && len < count) + { + const std::size_t remaining = count - len; + if (bufferSize > remaining) bufferSize = remaining; + } if (fileInputStream) { - fileInputStream.read(buffer.begin(), buffer.size()); + fileInputStream.read(buffer.begin(), bufferSize); n = fileInputStream.gcount(); } else n = 0; diff --git a/Net/src/StreamSocket.cpp b/Net/src/StreamSocket.cpp index 20023ed8a4..d71de4c23d 100644 --- a/Net/src/StreamSocket.cpp +++ b/Net/src/StreamSocket.cpp @@ -214,9 +214,9 @@ void StreamSocket::sendUrgent(unsigned char data) } -std::streamsize StreamSocket::sendFile(Poco::FileInputStream& fileInputStream, std::streamoff offset) +std::streamsize StreamSocket::sendFile(Poco::FileInputStream& fileInputStream, std::streamoff offset, std::streamsize count) { - return impl()->sendFile(fileInputStream, offset); + return impl()->sendFile(fileInputStream, offset, count); } diff --git a/Net/testsuite/src/SocketTest.cpp b/Net/testsuite/src/SocketTest.cpp index 52b0763343..31699ff332 100644 --- a/Net/testsuite/src/SocketTest.cpp +++ b/Net/testsuite/src/SocketTest.cpp @@ -15,6 +15,9 @@ #include "Poco/Net/StreamSocket.h" #include "Poco/Net/ServerSocket.h" #include "Poco/Net/SocketAddress.h" +#include "Poco/Net/TCPServerConnection.h" +#include "Poco/Net/TCPServerConnectionFactory.h" +#include "Poco/Net/TCPServer.h" #include "Poco/Net/NetException.h" #include "Poco/Timespan.h" #include "Poco/Stopwatch.h" @@ -25,6 +28,7 @@ #include "Poco/TemporaryFile.h" #include "Poco/FileStream.h" #include "Poco/Path.h" +#include "Poco/Thread.h" #include @@ -33,6 +37,9 @@ using Poco::Net::StreamSocket; using Poco::Net::ServerSocket; using Poco::Net::SocketAddress; using Poco::Net::ConnectionRefusedException; +using Poco::Net::TCPServerConnection; +using Poco::Net::TCPServerConnectionFactoryImpl; +using Poco::Net::TCPServer; using Poco::Timespan; using Poco::Stopwatch; using Poco::TimeoutException; @@ -44,6 +51,49 @@ using Poco::File; using Poco::delegate; +namespace +{ + class CopyToStringConnection: public TCPServerConnection + { + public: + CopyToStringConnection(const StreamSocket& s): + TCPServerConnection(s) + { + } + + void run() + { + _data.clear(); + StreamSocket& ss = socket(); + try + { + char buffer[256]; + int n = ss.receiveBytes(buffer, sizeof(buffer)); + while (n > 0) + { + _data.append(buffer, n); + n = ss.receiveBytes(buffer, sizeof(buffer)); + } + } + catch (Poco::Exception& exc) + { + std::cerr << "CopyToStringConnection: " << exc.displayText() << std::endl; + } + } + + static const std::string& data() + { + return _data; + } + + private: + static std::string _data; + }; + + std::string CopyToStringConnection::_data; +} + + SocketTest::SocketTest(const std::string& name): CppUnit::TestCase(name) { } @@ -671,9 +721,12 @@ void SocketTest::testUseFd() void SocketTest::testSendFile() { - EchoServer echoServer; + ServerSocket svs(0); + TCPServer srv(new TCPServerConnectionFactoryImpl(), svs); + srv.start(); + StreamSocket ss; - ss.connect(SocketAddress("127.0.0.1", echoServer.port())); + ss.connect(SocketAddress("127.0.0.1", srv.port())); std::string sentData = "Hello, world!"; @@ -683,28 +736,89 @@ void SocketTest::testSendFile() ostr.close(); Poco::FileInputStream istr(file.path()); - std::streamsize sent = 0; - while (sent < file.getSize()) + ss.sendFile(istr); + istr.close(); + ss.close(); + + while (srv.currentConnections() > 0) { - sent += ss.sendFile(istr, sent); + Poco::Thread::sleep(100); } + + assertTrue (CopyToStringConnection::data() == sentData); +} + + +void SocketTest::testSendFileLarge() +{ + ServerSocket svs(0); + TCPServer srv(new TCPServerConnectionFactoryImpl(), svs); + srv.start(); + + StreamSocket ss; + ss.connect(SocketAddress("127.0.0.1", srv.port())); + + std::string sentData; + + Poco::TemporaryFile file; + Poco::FileOutputStream ostr(file.path()); + std::string data("0123456789abcdef"); + for (int i = 0; i < 10000; i++) + { + ostr.write(data.data(), data.size()); + sentData += data; + } + ostr.close(); + + Poco::FileInputStream istr(file.path()); + ss.sendFile(istr); istr.close(); + ss.close(); - std::string receivedData; - char buffer[1024]; - int n = ss.receiveBytes(buffer, sizeof(buffer)); - while (n > 0) + while (srv.currentConnections() > 0) { - receivedData.append(buffer, n); - if (receivedData.size() < sentData.size()) - n = ss.receiveBytes(buffer, sizeof(buffer)); - else - n = 0; + Poco::Thread::sleep(100); } - assertTrue (receivedData == sentData); + assertTrue (CopyToStringConnection::data() == sentData); +} + + +void SocketTest::testSendFileRange() +{ + ServerSocket svs(0); + TCPServer srv(new TCPServerConnectionFactoryImpl(), svs); + srv.start(); + + StreamSocket ss; + ss.connect(SocketAddress("127.0.0.1", srv.port())); + + std::string sentData; + + Poco::TemporaryFile file; + Poco::FileOutputStream ostr(file.path()); + std::string data("0123456789abcdef"); + for (int i = 0; i < 1024; i++) + { + ostr.write(data.data(), data.size()); + sentData += data; + } + ostr.close(); + + const std::streamoff offset = 4000; + const std::streamsize count = 10000; + Poco::FileInputStream istr(file.path()); + ss.sendFile(istr, offset, count); + istr.close(); ss.close(); + + while (srv.currentConnections() > 0) + { + Poco::Thread::sleep(100); + } + + assertTrue (CopyToStringConnection::data() == sentData.substr(offset, count)); } @@ -766,6 +880,8 @@ CppUnit::Test* SocketTest::suite() CppUnit_addTest(pSuite, SocketTest, testUnixLocalAbstract); CppUnit_addTest(pSuite, SocketTest, testUseFd); CppUnit_addTest(pSuite, SocketTest, testSendFile); + CppUnit_addTest(pSuite, SocketTest, testSendFileLarge); + CppUnit_addTest(pSuite, SocketTest, testSendFileRange); return pSuite; } diff --git a/Net/testsuite/src/SocketTest.h b/Net/testsuite/src/SocketTest.h index af026e7d8c..2cc4d8f576 100644 --- a/Net/testsuite/src/SocketTest.h +++ b/Net/testsuite/src/SocketTest.h @@ -50,6 +50,8 @@ class SocketTest: public CppUnit::TestCase void testUnixLocalAbstract(); void testUseFd(); void testSendFile(); + void testSendFileLarge(); + void testSendFileRange(); void setUp() override; void tearDown() override; diff --git a/NetSSL_OpenSSL/testsuite/src/SecureStreamSocketTest.cpp b/NetSSL_OpenSSL/testsuite/src/SecureStreamSocketTest.cpp index dd04d621e2..ddf6006f1f 100644 --- a/NetSSL_OpenSSL/testsuite/src/SecureStreamSocketTest.cpp +++ b/NetSSL_OpenSSL/testsuite/src/SecureStreamSocketTest.cpp @@ -75,6 +75,45 @@ namespace } } }; + + class CopyToStringConnection: public TCPServerConnection + { + public: + CopyToStringConnection(const StreamSocket& s): + TCPServerConnection(s) + { + } + + void run() + { + _data.clear(); + StreamSocket& ss = socket(); + try + { + char buffer[256]; + int n = ss.receiveBytes(buffer, sizeof(buffer)); + while (n > 0) + { + _data.append(buffer, n); + n = ss.receiveBytes(buffer, sizeof(buffer)); + } + } + catch (Poco::Exception& exc) + { + std::cerr << "CopyToStringConnection: " << exc.displayText() << std::endl; + } + } + + static const std::string& data() + { + return _data; + } + + private: + static std::string _data; + }; + + std::string CopyToStringConnection::_data; } @@ -206,7 +245,7 @@ void SecureStreamSocketTest::testNB() void SecureStreamSocketTest::testSendFile() { SecureServerSocket svs(0); - TCPServer srv(new TCPServerConnectionFactoryImpl(), svs); + TCPServer srv(new TCPServerConnectionFactoryImpl(), svs); srv.start(); SecureStreamSocket ss; @@ -220,28 +259,92 @@ void SecureStreamSocketTest::testSendFile() ostr.close(); Poco::FileInputStream istr(file.path()); - std::streamsize sent = 0; - while (sent < file.getSize()) + ss.sendFile(istr); + istr.close(); + ss.close(); + + while (srv.currentConnections() > 0) + { + Poco::Thread::sleep(100); + } + + assertTrue (CopyToStringConnection::data() == sentData); +} + + +void SecureStreamSocketTest::testSendFileLarge() +{ + SecureServerSocket svs(0); + TCPServer srv(new TCPServerConnectionFactoryImpl(), svs); + srv.start(); + + SecureStreamSocket ss; + ss.connect(SocketAddress("127.0.0.1", srv.port())); + + std::string sentData; + + Poco::TemporaryFile file; + Poco::FileOutputStream ostr(file.path()); + std::string data("0123456789abcdef"); + for (int i = 0; i < 10000; i++) { - sent += ss.sendFile(istr, sent); + ostr.write(data.data(), data.size()); + sentData += data; } + ostr.close(); + + Poco::FileInputStream istr(file.path()); + ss.sendFile(istr); istr.close(); + ss.close(); - std::string receivedData; - char buffer[1024]; - int n = ss.receiveBytes(buffer, sizeof(buffer)); - while (n > 0) + while (srv.currentConnections() > 0) { - receivedData.append(buffer, n); - if (receivedData.size() < sentData.size()) - n = ss.receiveBytes(buffer, sizeof(buffer)); - else - n = 0; + Poco::Thread::sleep(100); } - assertTrue (receivedData == sentData); + assertTrue (CopyToStringConnection::data() == sentData); +} + + +void SecureStreamSocketTest::testSendFileRange() +{ + SecureServerSocket svs(0); + TCPServer srv(new TCPServerConnectionFactoryImpl(), svs); + srv.start(); + + SecureStreamSocket ss; + ss.connect(SocketAddress("127.0.0.1", srv.port())); + + std::string fileData; + Poco::TemporaryFile file; + Poco::FileOutputStream ostr(file.path()); + std::string data("0123456789abcdef"); + for (int i = 0; i < 1024; i++) + { + ostr.write(data.data(), data.size()); + fileData += data; + } + ostr.close(); + + const std::streamoff offset = 4000; + const std::streamsize count = 10000; + + Poco::FileInputStream istr(file.path()); + ss.sendFile(istr, offset, count); + istr.close(); ss.close(); + + while (srv.currentConnections() > 0) + { + Poco::Thread::sleep(100); + } + + std::cout << "\n" << fileData.size() << std::endl; + std::cout << "\n" << CopyToStringConnection::data().size() << std::endl; + + assertTrue (CopyToStringConnection::data() == fileData.substr(offset, count)); } @@ -263,6 +366,8 @@ CppUnit::Test* SecureStreamSocketTest::suite() CppUnit_addTest(pSuite, SecureStreamSocketTest, testPeek); CppUnit_addTest(pSuite, SecureStreamSocketTest, testNB); CppUnit_addTest(pSuite, SecureStreamSocketTest, testSendFile); + CppUnit_addTest(pSuite, SecureStreamSocketTest, testSendFileLarge); + CppUnit_addTest(pSuite, SecureStreamSocketTest, testSendFileRange); return pSuite; } diff --git a/NetSSL_OpenSSL/testsuite/src/SecureStreamSocketTest.h b/NetSSL_OpenSSL/testsuite/src/SecureStreamSocketTest.h index f072e90fc3..eb4486e22b 100644 --- a/NetSSL_OpenSSL/testsuite/src/SecureStreamSocketTest.h +++ b/NetSSL_OpenSSL/testsuite/src/SecureStreamSocketTest.h @@ -28,6 +28,8 @@ class SecureStreamSocketTest: public CppUnit::TestCase void testPeek(); void testNB(); void testSendFile(); + void testSendFileLarge(); + void testSendFileRange(); void setUp(); void tearDown(); From a1abf9659d9e85c07126816d5746310d99e9c25f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnter=20Obiltschnig?= Date: Sat, 8 Feb 2025 13:02:43 +0100 Subject: [PATCH 5/8] enh(Net): additional tests for StreamSocket::sendFile() --- Net/testsuite/src/SocketTest.cpp | 12 +++++++++--- .../testsuite/src/SecureStreamSocketTest.cpp | 15 +++++++++------ 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/Net/testsuite/src/SocketTest.cpp b/Net/testsuite/src/SocketTest.cpp index 31699ff332..162bfa5e21 100644 --- a/Net/testsuite/src/SocketTest.cpp +++ b/Net/testsuite/src/SocketTest.cpp @@ -736,7 +736,9 @@ void SocketTest::testSendFile() ostr.close(); Poco::FileInputStream istr(file.path()); - ss.sendFile(istr); + std::streamsize n = ss.sendFile(istr); + assertTrue (n == file.getSize()); + istr.close(); ss.close(); @@ -771,7 +773,9 @@ void SocketTest::testSendFileLarge() ostr.close(); Poco::FileInputStream istr(file.path()); - ss.sendFile(istr); + std::streamsize n = ss.sendFile(istr); + assertTrue (n == file.getSize()); + istr.close(); ss.close(); @@ -809,7 +813,9 @@ void SocketTest::testSendFileRange() const std::streamsize count = 10000; Poco::FileInputStream istr(file.path()); - ss.sendFile(istr, offset, count); + std::streamsize n = ss.sendFile(istr, offset, count); + assertTrue (n == count); + istr.close(); ss.close(); diff --git a/NetSSL_OpenSSL/testsuite/src/SecureStreamSocketTest.cpp b/NetSSL_OpenSSL/testsuite/src/SecureStreamSocketTest.cpp index ddf6006f1f..7521c22ba5 100644 --- a/NetSSL_OpenSSL/testsuite/src/SecureStreamSocketTest.cpp +++ b/NetSSL_OpenSSL/testsuite/src/SecureStreamSocketTest.cpp @@ -259,7 +259,9 @@ void SecureStreamSocketTest::testSendFile() ostr.close(); Poco::FileInputStream istr(file.path()); - ss.sendFile(istr); + std::streamsize n = ss.sendFile(istr); + assertTrue (n == file.getSize()); + istr.close(); ss.close(); @@ -294,7 +296,9 @@ void SecureStreamSocketTest::testSendFileLarge() ostr.close(); Poco::FileInputStream istr(file.path()); - ss.sendFile(istr); + std::streamsize n = ss.sendFile(istr); + assertTrue (n == file.getSize()); + istr.close(); ss.close(); @@ -332,7 +336,9 @@ void SecureStreamSocketTest::testSendFileRange() const std::streamsize count = 10000; Poco::FileInputStream istr(file.path()); - ss.sendFile(istr, offset, count); + std::streamsize n = ss.sendFile(istr, offset, count); + assertTrue (n == count); + istr.close(); ss.close(); @@ -341,9 +347,6 @@ void SecureStreamSocketTest::testSendFileRange() Poco::Thread::sleep(100); } - std::cout << "\n" << fileData.size() << std::endl; - std::cout << "\n" << CopyToStringConnection::data().size() << std::endl; - assertTrue (CopyToStringConnection::data() == fileData.substr(offset, count)); } From 24ff93107113d7efe722026c3f81e454ac7a4ff5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnter=20Obiltschnig?= Date: Sat, 8 Feb 2025 13:48:14 +0100 Subject: [PATCH 6/8] fix(Net): Issue concerning Net/CMakeLists.txt detection of HAVE_SENDFILE #4852 --- Net/CMakeLists.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Net/CMakeLists.txt b/Net/CMakeLists.txt index 2dea608a27..0989f0843d 100644 --- a/Net/CMakeLists.txt +++ b/Net/CMakeLists.txt @@ -10,7 +10,7 @@ POCO_HEADERS_AUTO(SRCS ${HDRS_G}) POCO_SOURCES_AUTO_PLAT(SRCS WIN32 src/wepoll.c) POCO_HEADERS_AUTO(SRCS src/wepoll.h) -if (MSVC) +if (MSVC OR MINGW) set(HAVE_SENDFILE ON) else() include(CheckIncludeFiles) @@ -18,8 +18,8 @@ else() check_include_files(sys/sendfile.h HAVE_SYS_SENDFILE_H) if(HAVE_SYS_SENDFILE_H) check_symbol_exists(sendfile sys/sendfile.h HAVE_SENDFILE) - if (NOT DEFINED HAVE_SENDFILE) - check_symbol_exists(sendfile64 sys/sendfile.h HAVE_SENDFILE) + if (NOT HAVE_SENDFILE) + check_symbol_exists(sendfile64 sys/sendfile.h HAVE_SENDFILE64) endif() else() # BSD version @@ -27,7 +27,7 @@ else() endif() endif() -if (DEFINED HAVE_SENDFILE) +if (HAVE_SENDFILE OR HAVE_SENDFILE64) message(STATUS "OS has native sendfile function") add_compile_definitions(POCO_HAVE_SENDFILE) endif() From db88e0ec00f3a8a824787af151f2ad5de13a4adb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnter=20Obiltschnig?= Date: Sat, 8 Feb 2025 15:20:14 +0100 Subject: [PATCH 7/8] fix(test): fix flaky test --- Net/testsuite/src/SocketTest.cpp | 18 +++++++++++++++--- .../testsuite/src/SecureStreamSocketTest.cpp | 18 +++++++++++++++--- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/Net/testsuite/src/SocketTest.cpp b/Net/testsuite/src/SocketTest.cpp index 162bfa5e21..b8632f50b6 100644 --- a/Net/testsuite/src/SocketTest.cpp +++ b/Net/testsuite/src/SocketTest.cpp @@ -63,7 +63,10 @@ namespace void run() { - _data.clear(); + { + Poco::FastMutex::ScopedLock lock(_mutex); + _data.clear(); + } StreamSocket& ss = socket(); try { @@ -71,7 +74,10 @@ namespace int n = ss.receiveBytes(buffer, sizeof(buffer)); while (n > 0) { - _data.append(buffer, n); + { + Poco::FastMutex::ScopedLock lock(_mutex); + _data.append(buffer, n); + } n = ss.receiveBytes(buffer, sizeof(buffer)); } } @@ -81,15 +87,18 @@ namespace } } - static const std::string& data() + static const std::string data() { + Poco::FastMutex::ScopedLock lock(_mutex); return _data; } private: + static Poco::FastMutex _mutex; static std::string _data; }; + Poco::FastMutex CopyToStringConnection::_mutex; std::string CopyToStringConnection::_data; } @@ -746,6 +755,7 @@ void SocketTest::testSendFile() { Poco::Thread::sleep(100); } + srv.stop(); assertTrue (CopyToStringConnection::data() == sentData); } @@ -783,6 +793,7 @@ void SocketTest::testSendFileLarge() { Poco::Thread::sleep(100); } + srv.stop(); assertTrue (CopyToStringConnection::data() == sentData); } @@ -823,6 +834,7 @@ void SocketTest::testSendFileRange() { Poco::Thread::sleep(100); } + srv.stop(); assertTrue (CopyToStringConnection::data() == sentData.substr(offset, count)); } diff --git a/NetSSL_OpenSSL/testsuite/src/SecureStreamSocketTest.cpp b/NetSSL_OpenSSL/testsuite/src/SecureStreamSocketTest.cpp index 7521c22ba5..0988bca396 100644 --- a/NetSSL_OpenSSL/testsuite/src/SecureStreamSocketTest.cpp +++ b/NetSSL_OpenSSL/testsuite/src/SecureStreamSocketTest.cpp @@ -86,7 +86,10 @@ namespace void run() { - _data.clear(); + { + Poco::FastMutex::ScopedLock lock(_mutex); + _data.clear(); + } StreamSocket& ss = socket(); try { @@ -94,7 +97,10 @@ namespace int n = ss.receiveBytes(buffer, sizeof(buffer)); while (n > 0) { - _data.append(buffer, n); + { + Poco::FastMutex::ScopedLock lock(_mutex); + _data.append(buffer, n); + } n = ss.receiveBytes(buffer, sizeof(buffer)); } } @@ -104,15 +110,18 @@ namespace } } - static const std::string& data() + static const std::string data() { + Poco::FastMutex::ScopedLock lock(_mutex); return _data; } private: + static Poco::FastMutex _mutex; static std::string _data; }; + Poco::FastMutex CopyToStringConnection::_mutex; std::string CopyToStringConnection::_data; } @@ -269,6 +278,7 @@ void SecureStreamSocketTest::testSendFile() { Poco::Thread::sleep(100); } + srv.stop(); assertTrue (CopyToStringConnection::data() == sentData); } @@ -306,6 +316,7 @@ void SecureStreamSocketTest::testSendFileLarge() { Poco::Thread::sleep(100); } + srv.stop(); assertTrue (CopyToStringConnection::data() == sentData); } @@ -346,6 +357,7 @@ void SecureStreamSocketTest::testSendFileRange() { Poco::Thread::sleep(100); } + srv.stop(); assertTrue (CopyToStringConnection::data() == fileData.substr(offset, count)); } From 47a77751fbdbf45ad69c1c4811023b4e4851d45f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnter=20Obiltschnig?= Date: Sat, 8 Feb 2025 18:04:36 +0100 Subject: [PATCH 8/8] fix(tests): another attempt at fixing the flaky testSendFile*() --- Net/testsuite/src/SocketTest.cpp | 3 +++ NetSSL_OpenSSL/testsuite/src/SecureStreamSocketTest.cpp | 3 +++ 2 files changed, 6 insertions(+) diff --git a/Net/testsuite/src/SocketTest.cpp b/Net/testsuite/src/SocketTest.cpp index b8632f50b6..27c180062b 100644 --- a/Net/testsuite/src/SocketTest.cpp +++ b/Net/testsuite/src/SocketTest.cpp @@ -751,6 +751,7 @@ void SocketTest::testSendFile() istr.close(); ss.close(); + Poco::Thread::sleep(200); while (srv.currentConnections() > 0) { Poco::Thread::sleep(100); @@ -789,6 +790,7 @@ void SocketTest::testSendFileLarge() istr.close(); ss.close(); + Poco::Thread::sleep(200); while (srv.currentConnections() > 0) { Poco::Thread::sleep(100); @@ -830,6 +832,7 @@ void SocketTest::testSendFileRange() istr.close(); ss.close(); + Poco::Thread::sleep(200); while (srv.currentConnections() > 0) { Poco::Thread::sleep(100); diff --git a/NetSSL_OpenSSL/testsuite/src/SecureStreamSocketTest.cpp b/NetSSL_OpenSSL/testsuite/src/SecureStreamSocketTest.cpp index 0988bca396..e0cc1a0494 100644 --- a/NetSSL_OpenSSL/testsuite/src/SecureStreamSocketTest.cpp +++ b/NetSSL_OpenSSL/testsuite/src/SecureStreamSocketTest.cpp @@ -274,6 +274,7 @@ void SecureStreamSocketTest::testSendFile() istr.close(); ss.close(); + Poco::Thread::sleep(200); while (srv.currentConnections() > 0) { Poco::Thread::sleep(100); @@ -312,6 +313,7 @@ void SecureStreamSocketTest::testSendFileLarge() istr.close(); ss.close(); + Poco::Thread::sleep(200); while (srv.currentConnections() > 0) { Poco::Thread::sleep(100); @@ -353,6 +355,7 @@ void SecureStreamSocketTest::testSendFileRange() istr.close(); ss.close(); + Poco::Thread::sleep(200); while (srv.currentConnections() > 0) { Poco::Thread::sleep(100);