From c73d97c9aae8d94918b9a79acfbb5e2a55ced963 Mon Sep 17 00:00:00 2001 From: Peter Johnson Date: Sun, 30 Dec 2018 09:12:12 -0800 Subject: [PATCH] Fix java example download (#18) The socket needed to be in blocking mode for sendfile to work with large file lengths. --- .../rpiConfigServer_src/MyHttpConnection.cpp | 64 ++++++++++++++----- 1 file changed, 48 insertions(+), 16 deletions(-) diff --git a/deps/tools/rpiConfigServer_src/MyHttpConnection.cpp b/deps/tools/rpiConfigServer_src/MyHttpConnection.cpp index 5c232ed..862988c 100644 --- a/deps/tools/rpiConfigServer_src/MyHttpConnection.cpp +++ b/deps/tools/rpiConfigServer_src/MyHttpConnection.cpp @@ -69,9 +69,10 @@ MyHttpConnection::MyHttpConnection(std::shared_ptr stream) }); } -class FsReq : public uv::RequestImpl { +class SendfileReq : public uv::RequestImpl { public: - FsReq() { + SendfileReq(uv_file out, uv_file in, int64_t inOffset, size_t len) + : m_out(out), m_in(in), m_inOffset(inOffset), m_len(len) { error = [this](uv::Error err) { GetLoop().error(err); }; } @@ -79,25 +80,51 @@ class FsReq : public uv::RequestImpl { return *static_cast(GetRaw()->loop->data); } + int Send(uv::Loop& loop) { + int err = uv_fs_sendfile(loop.GetRaw(), GetRaw(), m_out, m_in, m_inOffset, + m_len, [](uv_fs_t* req) { + auto& h = *static_cast(req->data); + if (req->result < 0) { + h.ReportError(req->result); + h.complete(); + h.Release(); + return; + } + + h.m_inOffset += req->result; + h.m_len -= req->result; + if (h.m_len == 0) { + // done + h.complete(); + h.Release(); // this is always a one-shot + return; + } + + // need to send more + h.Send(h.GetLoop()); + }); + if (err < 0) { + ReportError(err); + complete(); + } + return err; + } + wpi::sig::Signal<> complete; + + private: + uv_file m_out; + uv_file m_in; + int64_t m_inOffset; + size_t m_len; }; void Sendfile(uv::Loop& loop, uv_file out, uv_file in, int64_t inOffset, size_t len, std::function complete) { - auto req = std::make_shared(); + auto req = std::make_shared(out, in, inOffset, len); if (complete) req->complete.connect(complete); - int err = uv_fs_sendfile(loop.GetRaw(), req->GetRaw(), out, in, inOffset, len, - [](uv_fs_t* req) { - auto& h = *static_cast(req->data); - h.complete(); - h.Release(); // this is always a one-shot - }); - if (err < 0) { - loop.ReportError(err); - complete(); - } else { - req->Keep(); - } + int err = req->Send(loop); + if (err >= 0) req->Keep(); } void MyHttpConnection::SendFileResponse(int code, const wpi::Twine& codeText, @@ -134,10 +161,15 @@ void MyHttpConnection::SendFileResponse(int code, const wpi::Twine& codeText, SendData(os.bufs(), false); // close after write completes if we aren't keeping alive + // since we're using sendfile, set socket to blocking + m_stream.SetBlocking(true); Sendfile(m_stream.GetLoopRef(), outfd, infd, 0, status.getSize(), [ infd, closeAfter = !m_keepAlive, stream = &m_stream ] { ::close(infd); - if (closeAfter) stream->Close(); + if (closeAfter) + stream->Close(); + else + stream->SetBlocking(false); }); }