tools/net: Handle files which don't support sendfile
This adds a fallback read / write model.
Tested: ran against non-sendfile compatible file and it sent to the BMC successfully.
Change-Id: I6fd781ad19cd37376ca90743f799988e50ed460e
Signed-off-by: William A. Kennington III <wak@google.com>
Signed-off-by: Willy Tu <wltu@google.com>
diff --git a/tools/net.cpp b/tools/net.cpp
index 899824d..8b0663e 100644
--- a/tools/net.cpp
+++ b/tools/net.cpp
@@ -28,12 +28,11 @@
#include <ipmiblob/blob_errors.hpp>
#include <stdplus/handle/managed.hpp>
+#include <stdplus/util/cexec.hpp>
#include <cstdint>
#include <cstring>
-#include <memory>
#include <optional>
-#include <string>
#include <vector>
namespace
@@ -110,33 +109,58 @@
off_t offset = 0;
progress->start(fileSize);
+ auto confirmSend = [&]() {
+ if (bytesSent == 0)
+ {
+ return;
+ }
+ struct ipmi_flash::ExtChunkHdr chunk;
+ chunk.length = bytesSent;
+ std::vector<uint8_t> chunkBytes(sizeof(chunk));
+ std::memcpy(chunkBytes.data(), &chunk, sizeof(chunk));
+ /* This doesn't return anything on success. */
+ blob->writeBytes(session, offset - bytesSent, chunkBytes);
+ progress->updateProgress(bytesSent);
+ };
do
{
bytesSent = sys->sendfile(*connFd, *inputFd, &offset, blockSize);
if (bytesSent < 0)
{
- std::fprintf(stderr, "Failed to send data to BMC: %s\n",
- strerror(errno));
- progress->abort();
- return false;
+ // Not all input files support sendfile, fall back to a simple
+ // buffered mechanism if unsupported.
+ if (errno != EINVAL)
+ {
+ CHECK_ERRNO(-1, "Sending data to BMC");
+ }
+ std::array<uint8_t, 4096> buf;
+ size_t left = 0;
+ do
+ {
+ left += CHECK_ERRNO(sys->read(*inputFd, buf.data() + left,
+ buf.size() - left),
+ "Reading data for BMC");
+ bytesSent =
+ CHECK_ERRNO(sys->send(*connFd, buf.data(), left, 0),
+ "Sending data to BMC");
+ std::memmove(buf.data(), buf.data() + bytesSent,
+ left - bytesSent);
+ left -= bytesSent;
+ offset += bytesSent;
+ confirmSend();
+ } while (bytesSent > 0);
+ break;
}
- else if (bytesSent > 0)
- {
- /* Ok, so the data is staged, now send the blob write with
- * the details.
- */
- struct ipmi_flash::ExtChunkHdr chunk;
- chunk.length = bytesSent;
- std::vector<std::uint8_t> chunkBytes(sizeof(chunk));
- std::memcpy(chunkBytes.data(), &chunk, sizeof(chunk));
-
- /* This doesn't return anything on success. */
- blob->writeBytes(session, offset - bytesSent, chunkBytes);
- progress->updateProgress(bytesSent);
- }
+ confirmSend();
} while (bytesSent > 0);
}
+ catch (const std::system_error& e)
+ {
+ std::fprintf(stderr, "%s\n", e.what());
+ progress->abort();
+ return false;
+ }
catch (const ipmiblob::BlobException& b)
{
progress->abort();