xref: /openbmc/boost-dbus/include/dbus/message.hpp (revision b6e8327a)
1 // Copyright (c) Benjamin Kietzman (github.com/bkietz)
2 //
3 // Distributed under the Boost Software License, Version 1.0. (See accompanying
4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5 
6 #ifndef DBUS_MESSAGE_HPP
7 #define DBUS_MESSAGE_HPP
8 
9 #include <dbus/dbus.h>
10 #include <dbus/element.hpp>
11 #include <dbus/endpoint.hpp>
12 #include <dbus/impl/message_iterator.hpp>
13 #include <iostream>
14 #include <vector>
15 #include <boost/intrusive_ptr.hpp>
16 #include <boost/utility/enable_if.hpp>
17 
18 inline void intrusive_ptr_add_ref(DBusMessage* m) { dbus_message_ref(m); }
19 
20 inline void intrusive_ptr_release(DBusMessage* m) { dbus_message_unref(m); }
21 
22 namespace dbus {
23 
24 class message {
25   boost::intrusive_ptr<DBusMessage> message_;
26 
27  public:
28   /// Create a method call message
29   static message new_call(const endpoint& destination,
30                           const string& method_name) {
31     return dbus_message_new_method_call(
32         destination.get_process_name().c_str(), destination.get_path().c_str(),
33         destination.get_interface().c_str(), method_name.c_str());
34   }
35 
36   /// Create a method return message
37   static message new_return(message& call) {
38     return dbus_message_new_method_return(call);
39   }
40 
41   /// Create an error message
42   static message new_error(message& call, const string& error_name,
43                            const string& error_message) {
44     return dbus_message_new_error(call, error_name.c_str(),
45                                   error_message.c_str());
46   }
47 
48   /// Create a signal message
49   static message new_signal(const endpoint& origin, const string& signal_name) {
50     return dbus_message_new_signal(origin.get_path().c_str(),
51                                    origin.get_interface().c_str(),
52                                    signal_name.c_str());
53   }
54 
55   message() {}
56 
57   message(DBusMessage* m) : message_(dbus_message_ref(m)) {}
58 
59   operator DBusMessage*() { return message_.get(); }
60 
61   operator const DBusMessage*() const { return message_.get(); }
62 
63   string get_path() const {
64     return sanitize(dbus_message_get_path(message_.get()));
65   }
66 
67   string get_interface() const {
68     return sanitize(dbus_message_get_interface(message_.get()));
69   }
70 
71   string get_member() const {
72     return sanitize(dbus_message_get_member(message_.get()));
73   }
74 
75   string get_type() const {
76     return sanitize(
77         dbus_message_type_to_string(dbus_message_get_type(message_.get())));
78   }
79 
80   string get_sender() const {
81     return sanitize(dbus_message_get_sender(message_.get()));
82   }
83 
84   string get_destination() const {
85     return sanitize(dbus_message_get_destination(message_.get()));
86   }
87 
88   uint32 get_serial() { return dbus_message_get_serial(message_.get()); }
89 
90   message& set_serial(uint32 serial) {
91     dbus_message_set_serial(message_.get(), serial);
92     return *this;
93   }
94 
95   uint32 get_reply_serial() {
96     return dbus_message_get_reply_serial(message_.get());
97   }
98 
99   message& set_reply_serial(uint32 reply_serial) {
100     dbus_message_set_reply_serial(message_.get(), reply_serial);
101     return *this;
102   }
103 
104   struct packer {
105     impl::message_iterator iter_;
106     packer(message& m) { impl::message_iterator::init_append(m, iter_); }
107     template <typename Element>
108     packer& pack(const Element& e) {
109       return *this << e;
110     }
111   };
112   struct unpacker {
113     impl::message_iterator iter_;
114     unpacker(message& m) { impl::message_iterator::init(m, iter_); }
115 
116     template <typename Element>
117     unpacker& unpack(Element& e) {
118       return *this >> e;
119     }
120   };
121 
122   template <typename Element>
123   packer pack(const Element& e) {
124     return packer(*this).pack(e);
125   }
126 
127   template <typename Element>
128   unpacker unpack(Element& e) {
129     return unpacker(*this).unpack(e);
130   }
131 
132  private:
133   static std::string sanitize(const char* str) {
134     return (str == NULL) ? "(null)" : str;
135   }
136 };
137 
138 template <typename Element>
139 message::packer operator<<(message m, const Element& e) {
140   return message::packer(m).pack(e);
141 }
142 
143 template <typename Element>
144 typename boost::enable_if<is_fixed_type<Element>, message::packer&>::type
145 operator<<(message::packer& p, const Element& e) {
146   p.iter_.append_basic(element<Element>::code, &e);
147   return p;
148 }
149 
150 inline message::packer& operator<<(message::packer& p, const char* c) {
151   p.iter_.append_basic(element<string>::code, &c);
152   return p;
153 }
154 
155 inline message::packer& operator<<(message::packer& p, const string& e) {
156   const char* c = e.c_str();
157   return p << c;
158 }
159 
160 template <typename Element>
161 message::unpacker operator>>(message m, Element& e) {
162   return message::unpacker(m).unpack(e);
163 }
164 
165 template <typename Element>
166 typename boost::enable_if<is_fixed_type<Element>, message::unpacker&>::type
167 operator>>(message::unpacker& u, Element& e) {
168   u.iter_.get_basic(&e);
169   u.iter_.next();
170   return u;
171 }
172 
173 inline message::unpacker& operator>>(message::unpacker& u, string& s) {
174   const char* c;
175   u.iter_.get_basic(&c);
176   s.assign(c);
177   u.iter_.next();
178   return u;
179 }
180 
181 template <typename Element>
182 inline message::unpacker& operator>>(message::unpacker& u,
183                                      std::vector<Element>& s) {
184   static_assert(std::is_same<Element, std::string>::value, "only std::vector<std::string> is implemented for now");
185   impl::message_iterator sub;
186   u.iter_.recurse(sub);
187 
188   const char* c;
189   while (sub.has_next()) {
190     sub.get_basic(&c);
191     s.emplace_back(c);
192     sub.next();
193   }
194 
195   // TODO(ed)
196   // Make this generic for all types.  The below code is close, but there's
197   // template issues and things I don't understand;
198   /*
199   auto e = message::unpacker(sub);
200   while (sub.has_next()) {
201     s.emplace_back();
202     Element& element = s.back();
203     e.unpack(element);
204   }
205 */
206   return u;
207 }
208 
209 inline std::ostream& operator<<(std::ostream& os, const message& m) {
210   os << "type='" << m.get_type() << "',"
211      << "sender='" << m.get_sender() << "',"
212      << "interface='" << m.get_interface() << "',"
213      << "member='" << m.get_member() << "',"
214      << "path='" << m.get_path() << "',"
215      << "destination='" << m.get_destination() << "'";
216   return os;
217 }
218 
219 }  // namespace dbus
220 
221 #include <dbus/impl/message_iterator.ipp>
222 
223 #endif  // DBUS_MESSAGE_HPP
224