summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/ipmid/message.hpp18
-rw-r--r--include/ipmid/message/pack.hpp11
-rw-r--r--test/message/pack.cpp61
3 files changed, 72 insertions, 18 deletions
diff --git a/include/ipmid/message.hpp b/include/ipmid/message.hpp
index 4079eab..030618f 100644
--- a/include/ipmid/message.hpp
+++ b/include/ipmid/message.hpp
@@ -252,24 +252,6 @@ struct Payload
return packRet;
}
- /**
- * @brief pack a tuple of values (of any supported type) into the buffer
- *
- * This will pack the elements of the tuple as if each one was passed in
- * individually, as if passed into the above variadic function.
- *
- * @tparam Types - the implicitly declared list of the tuple element types
- *
- * @param t - the tuple of values to pack
- *
- * @return int - non-zero on pack errors
- */
- template <typename... Types>
- int pack(std::tuple<Types...>& t)
- {
- return std::apply([this](Types&... args) { return pack(args...); }, t);
- }
-
/******************************************************************
* Request operations
*****************************************************************/
diff --git a/include/ipmid/message/pack.hpp b/include/ipmid/message/pack.hpp
index 8a9abe1..4314ac1 100644
--- a/include/ipmid/message/pack.hpp
+++ b/include/ipmid/message/pack.hpp
@@ -93,6 +93,17 @@ struct PackSingle
}
};
+/** @brief Specialization of PackSingle for std::tuple<T> */
+template <typename... T>
+struct PackSingle<std::tuple<T...>>
+{
+ static int op(Payload& p, const std::tuple<T...>& v)
+ {
+ return std::apply([&p](const T&... args) { return p.pack(args...); },
+ v);
+ }
+};
+
/** @brief Specialization of PackSingle for std::string
* represented as a UCSD-Pascal style string
*/
diff --git a/test/message/pack.cpp b/test/message/pack.cpp
index 03846c5..d0a738a 100644
--- a/test/message/pack.cpp
+++ b/test/message/pack.cpp
@@ -156,6 +156,19 @@ TEST(PackBasics, Bitset32)
ASSERT_EQ(p.raw, k);
}
+TEST(PackBasics, Tuple)
+{
+ // tuples are the new struct, pack a tuple
+ ipmi::message::Payload p;
+ auto v = std::make_tuple(static_cast<uint16_t>(0x8604), 'A');
+ p.pack(v);
+ // check that the number of bytes matches
+ ASSERT_EQ(p.size(), sizeof(uint16_t) + sizeof(char));
+ // check that the bytes were correctly packed (LSB first)
+ std::vector<uint8_t> k = {0x04, 0x86, 0x41};
+ ASSERT_EQ(p.raw, k);
+}
+
TEST(PackBasics, Array4xUint8)
{
// an array of bytes will be output verbatim, low-order element first
@@ -363,3 +376,51 @@ TEST(PackAdvanced, UnalignedBitPacking)
std::vector<uint8_t> k = {0x96, 0xd2, 0x2a, 0xcd, 0xd3, 0x3b, 0xbc, 0x9d};
ASSERT_EQ(p.raw, k);
}
+
+TEST(PackAdvanced, ComplexOptionalTuple)
+{
+ constexpr size_t macSize = 6;
+ // inspired from a real-world case of Get Session Info
+ constexpr uint8_t handle = 0x23; // handle for active session
+ constexpr uint8_t maxSessions = 15; // number of possible active sessions
+ constexpr uint8_t currentSessions = 4; // number of current active sessions
+ std::optional< // only returned for active session
+ std::tuple<uint8_t, // user ID
+ uint8_t, // privilege
+ uint4_t, // channel number
+ uint4_t // protocol (RMCP+)
+ >>
+ activeSession;
+ std::optional< // only returned for channel type LAN
+ std::tuple<uint32_t, // IPv4 address
+ std::array<uint8_t, macSize>, // MAC address
+ uint16_t // port
+ >>
+ lanSession;
+
+ constexpr uint8_t userID = 7;
+ constexpr uint8_t priv = 4;
+ constexpr uint4_t channel = 2;
+ constexpr uint4_t protocol = 1;
+ activeSession.emplace(userID, priv, channel, protocol);
+ constexpr std::array<uint8_t, macSize> macAddr{0};
+ lanSession.emplace(0x0a010105, macAddr, 55327);
+
+ ipmi::message::Payload p;
+ p.pack(handle, maxSessions, currentSessions, activeSession, lanSession);
+ ASSERT_EQ(p.size(), sizeof(handle) + sizeof(maxSessions) +
+ sizeof(currentSessions) + 3 * sizeof(uint8_t) +
+ sizeof(uint32_t) + sizeof(uint8_t) * macSize +
+ sizeof(uint16_t));
+ uint8_t protocol_channel =
+ (static_cast<uint8_t>(protocol) << 4) | static_cast<uint8_t>(channel);
+ std::vector<uint8_t> k = {handle, maxSessions, currentSessions, userID,
+ priv, protocol_channel,
+ // ip addr
+ 0x05, 0x01, 0x01, 0x0a,
+ // mac addr
+ 0, 0, 0, 0, 0, 0,
+ // port
+ 0x1f, 0xd8};
+ ASSERT_EQ(p.raw, k);
+}
OpenPOWER on IntegriCloud