Add support for Unix file descriptors

Change-Id: I2d1402c38b7b8b39cee42f959a0421b24a80e45d
Signed-off-by: Waqar Hameed <waqarh@axis.com>
diff --git a/docs/interface.md b/docs/interface.md
index f32bd3b..f813e31 100644
--- a/docs/interface.md
+++ b/docs/interface.md
@@ -78,6 +78,7 @@
 * ...
 * uint64
 * double
+* unixfd
 * string
 * object_path
 * signature
diff --git a/sdbusplus/message/append.hpp b/sdbusplus/message/append.hpp
index 1a414d2..32d4b46 100644
--- a/sdbusplus/message/append.hpp
+++ b/sdbusplus/message/append.hpp
@@ -52,6 +52,11 @@
 struct can_append_multiple : std::true_type
 {
 };
+// unix_fd's int needs to be wrapped.
+template <>
+struct can_append_multiple<unix_fd> : std::false_type
+{
+};
 // std::string needs a c_str() call.
 template <>
 struct can_append_multiple<std::string> : std::false_type
@@ -166,6 +171,21 @@
 template <typename T>
 using append_single_t = append_single<types::details::type_id_downcast_t<T>>;
 
+/** @brief Specialization of append_single for details::unix_fd. */
+template <>
+struct append_single<details::unix_fd_type>
+{
+    template <typename T>
+    static void op(sdbusplus::SdBusInterface* intf, sd_bus_message* m, T&& s)
+    {
+        constexpr auto dbusType = std::get<0>(types::type_id<T>());
+        intf->sd_bus_message_append_basic(m, dbusType, &s.fd);
+
+        // sd-bus now owns the file descriptor
+        s.fd = -1;
+    }
+};
+
 /** @brief Specialization of append_single for std::strings. */
 template <>
 struct append_single<std::string>
diff --git a/sdbusplus/message/native_types.hpp b/sdbusplus/message/native_types.hpp
index b67c7e1..efa0d3f 100644
--- a/sdbusplus/message/native_types.hpp
+++ b/sdbusplus/message/native_types.hpp
@@ -80,6 +80,16 @@
 struct signature_type
 {
 };
+/** Typename for sdbus UNIX_FD types. */
+struct unix_fd_type
+{
+    int fd;
+
+    operator int() const
+    {
+        return fd;
+    }
+};
 
 } // namespace details
 
@@ -87,6 +97,7 @@
 using object_path = details::string_wrapper<details::object_path_type>;
 /** std::string wrapper for SIGNATURE. */
 using signature = details::string_wrapper<details::signature_type>;
+using unix_fd = details::unix_fd_type;
 
 } // namespace message
 } // namespace sdbusplus
diff --git a/sdbusplus/message/read.hpp b/sdbusplus/message/read.hpp
index 2035d30..7a99570 100644
--- a/sdbusplus/message/read.hpp
+++ b/sdbusplus/message/read.hpp
@@ -51,6 +51,11 @@
 struct can_read_multiple : std::true_type
 {
 };
+// unix_fd's int needs to be wrapped
+template <>
+struct can_read_multiple<unix_fd> : std::false_type
+{
+};
 // std::string needs a char* conversion.
 template <>
 struct can_read_multiple<std::string> : std::false_type
@@ -150,6 +155,23 @@
 template <typename T>
 using read_single_t = read_single<types::details::type_id_downcast_t<T>>;
 
+/** @brief Specialization of read_single for details::unix_fd. */
+template <>
+struct read_single<details::unix_fd_type>
+{
+    template <typename T>
+    static void op(sdbusplus::SdBusInterface* intf, sd_bus_message* m, T&& s)
+    {
+        constexpr auto dbusType = std::get<0>(types::type_id<T>());
+        int r = intf->sd_bus_message_read_basic(m, dbusType, &s.fd);
+        if (r < 0)
+        {
+            throw exception::SdBusError(-r,
+                                        "sd_bus_message_read_basic unix_fd");
+        }
+    }
+};
+
 /** @brief Specialization of read_single for std::strings. */
 template <>
 struct read_single<std::string>
diff --git a/sdbusplus/message/types.hpp b/sdbusplus/message/types.hpp
index 141c656..eb7407f 100644
--- a/sdbusplus/message/types.hpp
+++ b/sdbusplus/message/types.hpp
@@ -219,6 +219,10 @@
 {
 };
 template <>
+struct type_id<unix_fd> : tuple_type_id<SD_BUS_TYPE_UNIX_FD>
+{
+};
+template <>
 struct type_id<std::string> : tuple_type_id<SD_BUS_TYPE_STRING>
 {
 };
diff --git a/tools/sdbusplus/property.py b/tools/sdbusplus/property.py
index 33c7e25..fb774b6 100644
--- a/tools/sdbusplus/property.py
+++ b/tools/sdbusplus/property.py
@@ -114,6 +114,7 @@
             'int64': {'cppName': 'int64_t', 'params': 0},
             'uint64': {'cppName': 'uint64_t', 'params': 0},
             'double': {'cppName': 'double', 'params': 0},
+            'unixfd': {'cppName': 'sdbusplus::message::unix_fd', 'params': 0},
             'string': {'cppName': 'std::string', 'params': 0},
             'path': {'cppName': 'sdbusplus::message::object_path',
                      'params': 0},