tools: implement bt sendcontents
Implement the block transfer (really not blocktransfer only)
sendcontents handler. This handler sends the file contents within
the IPMI packets themselves.
Note: This is really used for kcs, etc, but it's called bt to avoid
confusion with general ipmi code.
Change-Id: I310034a6afdf0eb25894e658ccee42e6394aa4d2
Signed-off-by: Patrick Venture <venture@google.com>
diff --git a/test/Makefile.am b/test/Makefile.am
index 3d51fa4..0b01997 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -28,6 +28,7 @@
firmware_commit_unittest \
file_handler_unittest \
tools_blob_unittest \
+ tools_bt_unittest \
tools_updater_unittest \
tools_ipmi_unittest
@@ -72,6 +73,9 @@
tools_blob_unittest_SOURCES = tools_blob_unittest.cpp
tools_blob_unittest_LDADD = $(top_builddir)/tools/blob_handler.o
+tools_bt_unittest_SOURCES = tools_bt_unittest.cpp
+tools_bt_unittest_LDADD = $(top_builddir)/tools/bt.o
+
tools_updater_unittest_SOURCES = tools_updater_unittest.cpp
tools_updater_unittest_LDADD = $(top_builddir)/tools/updater.o
diff --git a/test/tools_bt_unittest.cpp b/test/tools_bt_unittest.cpp
new file mode 100644
index 0000000..24511c3
--- /dev/null
+++ b/test/tools_bt_unittest.cpp
@@ -0,0 +1,48 @@
+#include "blob_interface_mock.hpp"
+#include "bt.hpp"
+#include "internal_sys_mock.hpp"
+
+#include <cstring>
+
+#include <gtest/gtest.h>
+
+namespace host_tool
+{
+
+using ::testing::_;
+using ::testing::ContainerEq;
+using ::testing::Eq;
+using ::testing::Invoke;
+using ::testing::NotNull;
+using ::testing::Return;
+
+TEST(BtHandlerTest, verifySendsFileContents)
+{
+ /* In this very basic test, we'll feed the bt handler data from the internal
+ * syscall mock and catch the writes via the blob mock.
+ */
+ internal::InternalSysMock sysMock;
+ BlobInterfaceMock blobMock;
+
+ BtDataHandler handler(&blobMock, &sysMock);
+ std::string filePath = "/asdf";
+ int fd = 1;
+ std::uint16_t session = 0xbeef;
+ std::vector<std::uint8_t> bytes = {'1', '2', '3', '4'};
+
+ EXPECT_CALL(sysMock, open(Eq(filePath), _)).WillOnce(Return(fd));
+ EXPECT_CALL(sysMock, read(fd, NotNull(), _))
+ .WillOnce(Invoke([&](int fd, void* buf, std::size_t count) {
+ EXPECT_TRUE(count > bytes.size());
+ std::memcpy(buf, bytes.data(), bytes.size());
+ return bytes.size();
+ }))
+ .WillOnce(Return(0));
+ EXPECT_CALL(sysMock, close(fd)).WillOnce(Return(0));
+
+ EXPECT_CALL(blobMock, writeBytes(session, 0, ContainerEq(bytes)));
+
+ EXPECT_TRUE(handler.sendContents(filePath, session));
+}
+
+} // namespace host_tool
diff --git a/tools/bt.cpp b/tools/bt.cpp
index da582d4..297bc30 100644
--- a/tools/bt.cpp
+++ b/tools/bt.cpp
@@ -1,12 +1,50 @@
#include "bt.hpp"
+#include "blob_errors.hpp"
+
+#include <cstdint>
+#include <vector>
+
namespace host_tool
{
bool BtDataHandler::sendContents(const std::string& input,
std::uint16_t session)
{
- return false;
+ int inputFd = sys->open(input.c_str(), 0);
+ if (inputFd < 0)
+ {
+ return false;
+ }
+
+ static constexpr int btBufferLen = 50;
+ std::uint8_t readBuffer[btBufferLen];
+ int bytesRead;
+ std::uint32_t offset = 0;
+
+ try
+ {
+ do
+ {
+ bytesRead = sys->read(inputFd, readBuffer, sizeof(readBuffer));
+ if (bytesRead > 0)
+ {
+ /* minorly awkward repackaging. */
+ std::vector<std::uint8_t> buffer(&readBuffer[0],
+ &readBuffer[bytesRead]);
+ blob->writeBytes(session, offset, buffer);
+ offset += bytesRead;
+ }
+ } while (bytesRead > 0);
+ }
+ catch (const BlobException& b)
+ {
+ sys->close(inputFd);
+ return false;
+ }
+
+ sys->close(inputFd);
+ return true;
}
} // namespace host_tool