Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using native sendfile from OS for HttpServer #4351

Merged
merged 11 commits into from
Sep 1, 2024
2 changes: 0 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -242,8 +242,6 @@ if (POCO_ENABLE_STD_MUTEX)
add_definitions(-DPOCO_ENABLE_STD_MUTEX)
endif ()

option(POCO_USE_SENDFILE_FOR_HTTPSERVER "Set to OFF|ON using native sendFile function from OS for http server method HTTPServerResponse::sendFile" OFF)

include(DefinePlatformSpecifc)

# Collect the built libraries and include dirs, the will be used to create the PocoConfig.cmake file
Expand Down
4 changes: 2 additions & 2 deletions Foundation/include/Poco/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -212,8 +212,8 @@
// #define POCO_ENABLE_STD_MUTEX
#endif

#ifndef POCO_USE_SENDFILE_FOR_HTTPSERVER
// #define POCO_USE_SENDFILE_FOR_HTTPSERVER
#ifndef POCO_HAVE_SENDFILE
// #define POCO_HAVE_SENDFILE
#endif

#define POCO_HAVE_CPP17_COMPILER (__cplusplus >= 201703L)
Expand Down
2 changes: 1 addition & 1 deletion Foundation/include/Poco/FileStream.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ class Foundation_API FileIOS: public virtual std::ios
NativeHandle nativeHandle() const;
/// Returns native file descriptor handle

Poco::UInt64 size() const;
UIntPtr size() const;
bas524 marked this conversation as resolved.
Show resolved Hide resolved
/// Returns file size

protected:
Expand Down
2 changes: 1 addition & 1 deletion Foundation/include/Poco/FileStream_POSIX.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class Foundation_API FileStreamBuf: public BufferedBidirectionalStreamBuf
NativeHandle nativeHandle() const;
/// Returns native file descriptor handle

Poco::UInt64 size() const;
UIntPtr size() const;
bas524 marked this conversation as resolved.
Show resolved Hide resolved
/// Returns file size

protected:
Expand Down
2 changes: 0 additions & 2 deletions Foundation/include/Poco/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ using UInt64 = std::uint64_t;
using IntPtr = std::intptr_t;
using UIntPtr = std::uintptr_t;


#if defined(_MSC_VER)
#if defined(_WIN64)
#define POCO_PTR_IS_64_BIT 1
Expand Down Expand Up @@ -72,7 +71,6 @@ using UIntPtr = std::uintptr_t;
#define POCO_HAVE_INT64 1
#endif


} // namespace Poco


Expand Down
2 changes: 1 addition & 1 deletion Foundation/src/FileStream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ FileIOS::NativeHandle FileIOS::nativeHandle() const
}


Poco::UInt64 FileIOS::size() const {
Poco::UIntPtr FileIOS::size() const {
return _buf.size();
}

Expand Down
2 changes: 1 addition & 1 deletion Foundation/src/FileStream_POSIX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ FileStreamBuf::NativeHandle FileStreamBuf::nativeHandle() const
return _fd;
}

Poco::UInt64 FileStreamBuf::size() const
Poco::UIntPtr FileStreamBuf::size() const
{
struct stat stat_buf;
int rc = fstat(_fd, &stat_buf);
Expand Down
22 changes: 20 additions & 2 deletions Net/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,26 @@ POCO_HEADERS_AUTO(SRCS ${HDRS_G})
POCO_SOURCES_AUTO_PLAT(SRCS WIN32 src/wepoll.c)
POCO_HEADERS_AUTO(SRCS src/wepoll.h)

if (POCO_USE_SENDFILE_FOR_HTTPSERVER)
add_definitions(-DPOCO_USE_SENDFILE_FOR_HTTPSERVER)
if (MSVC)
set(HAVE_SENDFILE ON)
else()
include(CheckIncludeFiles)
include(CheckSymbolExists)
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)
endif()
else()
# BSD version
check_symbol_exists(sendfile "sys/types.h;sys/socket.h;sys/uio.h" HAVE_SENDFILE)
endif()
endif()

if (DEFINED HAVE_SENDFILE)
message(STATUS "OS has native sendfile function")
add_definitions(-DPOCO_HAVE_SENDFILE)
endif()

# Version Resource
Expand Down
11 changes: 8 additions & 3 deletions Net/include/Poco/Net/SocketImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -477,12 +477,17 @@ class Net_API SocketImpl: public Poco::RefCountedObject

bool initialized() const;
/// Returns true iff the underlying socket is initialized.

Poco::Int64 sendFile(FileInputStream &FileInputStream, Poco::UInt64 offset = 0);
#ifdef POCO_HAVE_SENDFILE
IntPtr sendFile(FileInputStream &FileInputStream, UIntPtr offset = 0);
bas524 marked this conversation as resolved.
Show resolved Hide resolved
/// 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.
Expand Down
11 changes: 8 additions & 3 deletions Net/include/Poco/Net/StreamSocket.h
Original file line number Diff line number Diff line change
Expand Up @@ -257,12 +257,17 @@ class Net_API StreamSocket: public Socket
///
/// The preferred way for a socket to receive urgent data
/// is by enabling the SO_OOBINLINE option.

Poco::Int64 sendFile(FileInputStream &FileInputStream, Poco::UInt64 offset = 0);
#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(...)

///
/// 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
StreamSocket(SocketImpl* pImpl);
/// Creates the Socket and attaches the given SocketImpl.
/// The socket takes ownership of the SocketImpl.
Expand Down
14 changes: 8 additions & 6 deletions Net/src/HTTPServerResponseImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
#include "Poco/FileStream.h"
#include "Poco/DateTimeFormatter.h"
#include "Poco/DateTimeFormat.h"
#include "Poco/Error.h"
#include "Poco/Net/NetException.h"


using Poco::File;
Expand All @@ -37,6 +39,7 @@ using Poco::StreamCopier;
using Poco::OpenFileException;
using Poco::DateTimeFormatter;
using Poco::DateTimeFormat;
using Poco::Error;


namespace Poco {
Expand Down Expand Up @@ -128,16 +131,15 @@ void HTTPServerResponseImpl::sendFile(const std::string& path, const std::string
write(*_pStream);
if (_pRequest && _pRequest->getMethod() != HTTPRequest::HTTP_HEAD)
{
#ifdef POCO_USE_SENDFILE_FOR_HTTPSERVER
delete _pStream; // delete the stream to flush the HTTP headers to the socket, required by HTTP 1.0 and above
_pStream = nullptr;
#ifdef POCO_HAVE_SENDFILE
_pStream->flush(); // flush the HTTP headers to the socket, required by HTTP 1.0 and above

Poco::Int64 sent = 0;
Poco::Int64 offset = 0;
Poco::IntPtr sent = 0;
Poco::IntPtr offset = 0;
while (sent < length)
bas524 marked this conversation as resolved.
Show resolved Hide resolved
{
offset = sent;
sent = _session.socket().sendFile(istr, offset);
sent += _session.socket().sendFile(istr, offset);
}
#else
StreamCopier::copyStream(istr, *_pStream);
Expand Down
30 changes: 18 additions & 12 deletions Net/src/SocketImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
using sighandler_t = sig_t;
#endif

#if POCO_OS == POCO_OS_LINUX && !defined(POCO_EMSCRIPTEN)
#if POCO_OS == POCO_OS_LINUX && defined(POCO_HAVE_SENDFILE)
#include <sys/sendfile.h>
#endif

Expand Down Expand Up @@ -1372,12 +1372,12 @@ void SocketImpl::error(int code, const std::string& arg)
throw IOException(NumberFormatter::format(code), arg, code);
}
}

#ifdef POCO_HAVE_SENDFILE
bas524 marked this conversation as resolved.
Show resolved Hide resolved
#ifdef POCO_OS_FAMILY_WINDOWS
Poco::Int64 SocketImpl::sendFile(FileInputStream &fileInputStream, Poco::UInt64 offset)
IntPtr SocketImpl::sendFile(FileInputStream &fileInputStream, UIntPtr offset)
{
FileIOS::NativeHandle fd = fileInputStream.nativeHandle();
Poco::UInt64 fileSize = fileInputStream.size();
UIntPtr fileSize = fileInputStream.size();
std::streamoff sentSize = fileSize - offset;
LARGE_INTEGER offsetHelper;
offsetHelper.QuadPart = offset;
Expand All @@ -1388,29 +1388,30 @@ Poco::Int64 SocketImpl::sendFile(FileInputStream &fileInputStream, Poco::UInt64
overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (overlapped.hEvent == nullptr)
{
return -1;
int err = GetLastError();
error(err, std::string("[sendfile error]") + Error::getMessage(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)) {
CloseHandle(overlapped.hEvent);
error(err, Error::getMessage(err));
error(err, std::string("[sendfile error]") + Error::getMessage(err));
}
WaitForSingleObject(overlapped.hEvent, INFINITE);
}
CloseHandle(overlapped.hEvent);
return sentSize;
}
#else
Poco::Int64 _sendfile(poco_socket_t sd, FileIOS::NativeHandle fd, Poco::UInt64 offset,std::streamoff sentSize)
IntPtr _sendfile(poco_socket_t sd, FileIOS::NativeHandle fd, UIntPtr offset, std::streamoff sentSize)
{
Poco::Int64 sent = 0;
IntPtr sent = 0;
#ifdef __USE_LARGEFILE64
sent = sendfile64(sd, fd, (off64_t *)&offset, sentSize);
#else
#if POCO_OS == POCO_OS_LINUX && !defined(POCO_EMSCRIPTEN)
#if POCO_OS == POCO_OS_LINUX
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);
Expand All @@ -1433,21 +1434,26 @@ Poco::Int64 _sendfile(poco_socket_t sd, FileIOS::NativeHandle fd, Poco::UInt64 o
return sent;
}

Poco::Int64 SocketImpl::sendFile(FileInputStream &fileInputStream, Poco::UInt64 offset)
IntPtr SocketImpl::sendFile(FileInputStream &fileInputStream, UIntPtr offset)
{
FileIOS::NativeHandle fd = fileInputStream.nativeHandle();
Poco::UInt64 fileSize = fileInputStream.size();
UIntPtr fileSize = fileInputStream.size();
std::streamoff sentSize = fileSize - offset;
Poco::Int64 sent = 0;
IntPtr sent = 0;
bas524 marked this conversation as resolved.
Show resolved Hide resolved
sighandler_t sigPrev = signal(SIGPIPE, SIG_IGN);
while (sent == 0)
{
errno = 0;
sent = _sendfile(_sockfd, fd, offset, sentSize);
if (sent < 0)
{
error(errno, std::string("[sendfile error]") + Error::getMessage(errno));
bas524 marked this conversation as resolved.
Show resolved Hide resolved
}
}
signal(SIGPIPE, sigPrev != SIG_ERR ? sigPrev : SIG_DFL);
return sent;
}
#endif // POCO_OS_FAMILY_WINDOWS
#endif // POCO_HAVE_SENDFILE

} } // namespace Poco::Net
6 changes: 3 additions & 3 deletions Net/src/StreamSocket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -212,10 +212,10 @@ void StreamSocket::sendUrgent(unsigned char data)
{
impl()->sendUrgent(data);
}

Poco::Int64 StreamSocket::sendFile(FileInputStream &fileInputStream, Poco::UInt64 offset)
#ifdef POCO_HAVE_SENDFILE
IntPtr StreamSocket::sendFile(FileInputStream &fileInputStream, UIntPtr offset)
{
return impl()->sendFile(fileInputStream, offset);
}

#endif
} } // namespace Poco::Net
8 changes: 5 additions & 3 deletions Net/testsuite/src/SocketStreamTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ void SocketStreamTest::testEOF()
ss.close();
}

#ifdef POCO_HAVE_SENDFILE
void SocketStreamTest::testSendFile()
{
const int fileSize = 64000;
Expand All @@ -147,11 +148,11 @@ void SocketStreamTest::testSendFile()

SocketStream str(ss);

Poco::UInt64 offset = 0;
Poco::Int64 sent = 0;
Poco::UIntPtr offset = 0;
Poco::IntPtr sent = 0;
try
{
sent = ss.sendFile(fin);
sent = ss.sendFile(fin);
}
catch (Poco::NotImplementedException &)
{
Expand Down Expand Up @@ -180,6 +181,7 @@ void SocketStreamTest::testSendFile()
File f(fileName);
f.remove();
}
#endif

void SocketStreamTest::setUp()
{
Expand Down
2 changes: 2 additions & 0 deletions Net/testsuite/src/SocketStreamTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ class SocketStreamTest: public CppUnit::TestCase
void testStreamEcho();
void testLargeStreamEcho();
void testEOF();
#ifdef POCO_HAVE_SENDFILE
void testSendFile();
#endif

void setUp();
void tearDown();
Expand Down
Loading