1 /** 2 * (C) 2016 - 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland 3 * (C) 2016 - 2019 Stanislav Angelovic <angelovic.s@gmail.com> 4 * 5 * @file Message.h 6 * 7 * Created on: Nov 9, 2016 8 * Project: sdbus-c++ 9 * Description: High-level D-Bus IPC C++ library based on sd-bus 10 * 11 * This file is part of sdbus-c++. 12 * 13 * sdbus-c++ is free software; you can redistribute it and/or modify it 14 * under the terms of the GNU Lesser General Public License as published by 15 * the Free Software Foundation, either version 2.1 of the License, or 16 * (at your option) any later version. 17 * 18 * sdbus-c++ is distributed in the hope that it will be useful, 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 * GNU Lesser General Public License for more details. 22 * 23 * You should have received a copy of the GNU Lesser General Public License 24 * along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>. 25 */ 26 27 #ifndef SDBUS_CXX_MESSAGE_H_ 28 #define SDBUS_CXX_MESSAGE_H_ 29 30 #include <sdbus-c++/TypeTraits.h> 31 #include <sdbus-c++/Error.h> 32 #include <string> 33 #include <vector> 34 #include <map> 35 #include <memory> 36 #include <utility> 37 #include <cstdint> 38 #include <cassert> 39 #include <functional> 40 #include <sys/types.h> 41 42 // Forward declarations 43 namespace sdbus { 44 class Variant; 45 class ObjectPath; 46 class Signature; 47 template <typename... _ValueTypes> class Struct; 48 class UnixFd; 49 class MethodReply; 50 namespace internal { 51 class ISdBus; 52 class IConnection; 53 } 54 } 55 56 namespace sdbus { 57 58 // Assume the caller has already obtained message ownership 59 struct adopt_message_t { explicit adopt_message_t() = default; }; 60 inline constexpr adopt_message_t adopt_message{}; 61 62 /********************************************//** 63 * @class Message 64 * 65 * Message represents a D-Bus message, which can be either method call message, 66 * method reply message, signal message, or a plain message serving as a storage 67 * for serialized data. 68 * 69 * Serialization and deserialization functions are provided for types supported 70 * by D-Bus. 71 * 72 * You don't need to work with this class directly if you use high-level APIs 73 * of @c IObject and @c IProxy. 74 * 75 ***********************************************/ 76 class [[nodiscard]] Message 77 { 78 public: 79 Message& operator<<(bool item); 80 Message& operator<<(int16_t item); 81 Message& operator<<(int32_t item); 82 Message& operator<<(int64_t item); 83 Message& operator<<(uint8_t item); 84 Message& operator<<(uint16_t item); 85 Message& operator<<(uint32_t item); 86 Message& operator<<(uint64_t item); 87 Message& operator<<(double item); 88 Message& operator<<(const char *item); 89 Message& operator<<(const std::string &item); 90 Message& operator<<(const Variant &item); 91 Message& operator<<(const ObjectPath &item); 92 Message& operator<<(const Signature &item); 93 Message& operator<<(const UnixFd &item); 94 95 Message& operator>>(bool& item); 96 Message& operator>>(int16_t& item); 97 Message& operator>>(int32_t& item); 98 Message& operator>>(int64_t& item); 99 Message& operator>>(uint8_t& item); 100 Message& operator>>(uint16_t& item); 101 Message& operator>>(uint32_t& item); 102 Message& operator>>(uint64_t& item); 103 Message& operator>>(double& item); 104 Message& operator>>(char*& item); 105 Message& operator>>(std::string &item); 106 Message& operator>>(Variant &item); 107 Message& operator>>(ObjectPath &item); 108 Message& operator>>(Signature &item); 109 Message& operator>>(UnixFd &item); 110 111 Message& openContainer(const std::string& signature); 112 Message& closeContainer(); 113 Message& openDictEntry(const std::string& signature); 114 Message& closeDictEntry(); 115 Message& openVariant(const std::string& signature); 116 Message& closeVariant(); 117 Message& openStruct(const std::string& signature); 118 Message& closeStruct(); 119 120 Message& enterContainer(const std::string& signature); 121 Message& exitContainer(); 122 Message& enterDictEntry(const std::string& signature); 123 Message& exitDictEntry(); 124 Message& enterVariant(const std::string& signature); 125 Message& exitVariant(); 126 Message& enterStruct(const std::string& signature); 127 Message& exitStruct(); 128 129 explicit operator bool() const; 130 void clearFlags(); 131 132 std::string getInterfaceName() const; 133 std::string getMemberName() const; 134 std::string getSender() const; 135 std::string getPath() const; 136 std::string getDestination() const; 137 void peekType(std::string& type, std::string& contents) const; 138 bool isValid() const; 139 bool isEmpty() const; 140 141 void copyTo(Message& destination, bool complete) const; 142 void seal(); 143 void rewind(bool complete); 144 145 pid_t getCredsPid() const; 146 uid_t getCredsUid() const; 147 uid_t getCredsEuid() const; 148 gid_t getCredsGid() const; 149 gid_t getCredsEgid() const; 150 std::vector<gid_t> getCredsSupplementaryGids() const; 151 std::string getSELinuxContext() const; 152 153 class Factory; 154 155 protected: 156 Message() = default; 157 explicit Message(internal::ISdBus* sdbus) noexcept; 158 Message(void *msg, internal::ISdBus* sdbus) noexcept; 159 Message(void *msg, internal::ISdBus* sdbus, adopt_message_t) noexcept; 160 161 Message(const Message&) noexcept; 162 Message& operator=(const Message&) noexcept; 163 Message(Message&& other) noexcept; 164 Message& operator=(Message&& other) noexcept; 165 166 ~Message(); 167 168 friend Factory; 169 170 protected: 171 void* msg_{}; 172 internal::ISdBus* sdbus_{}; 173 mutable bool ok_{true}; 174 }; 175 176 struct dont_request_slot_t { explicit dont_request_slot_t() = default; }; 177 inline constexpr dont_request_slot_t dont_request_slot{}; 178 179 class MethodCall : public Message 180 { 181 using Message::Message; 182 friend Factory; 183 184 public: 185 using Slot = std::unique_ptr<void, std::function<void(void*)>>; 186 187 MethodCall() = default; 188 189 MethodReply send(uint64_t timeout) const; 190 void send(void* callback, void* userData, uint64_t timeout, dont_request_slot_t) const; 191 [[nodiscard]] Slot send(void* callback, void* userData, uint64_t timeout) const; 192 193 MethodReply createReply() const; 194 MethodReply createErrorReply(const sdbus::Error& error) const; 195 196 void dontExpectReply(); 197 bool doesntExpectReply() const; 198 199 protected: 200 MethodCall(void *msg, internal::ISdBus* sdbus, const internal::IConnection* connection, adopt_message_t) noexcept; 201 202 private: 203 MethodReply sendWithReply(uint64_t timeout = 0) const; 204 MethodReply sendWithNoReply() const; 205 const internal::IConnection* connection_{}; 206 }; 207 208 class MethodReply : public Message 209 { 210 using Message::Message; 211 friend Factory; 212 213 public: 214 MethodReply() = default; 215 void send() const; 216 }; 217 218 class Signal : public Message 219 { 220 using Message::Message; 221 friend Factory; 222 223 public: 224 Signal() = default; 225 void setDestination(const std::string& destination); 226 void send() const; 227 }; 228 229 class PropertySetCall : public Message 230 { 231 using Message::Message; 232 friend Factory; 233 234 public: 235 PropertySetCall() = default; 236 }; 237 238 class PropertyGetReply : public Message 239 { 240 using Message::Message; 241 friend Factory; 242 243 public: 244 PropertyGetReply() = default; 245 }; 246 247 class PlainMessage : public Message 248 { 249 using Message::Message; 250 friend Factory; 251 252 public: 253 PlainMessage() = default; 254 }; 255 256 template <typename _Element> 257 inline Message& operator<<(Message& msg, const std::vector<_Element>& items) 258 { 259 msg.openContainer(signature_of<_Element>::str()); 260 261 for (const auto& item : items) 262 msg << item; 263 264 msg.closeContainer(); 265 266 return msg; 267 } 268 269 template <typename _Key, typename _Value> 270 inline Message& operator<<(Message& msg, const std::map<_Key, _Value>& items) 271 { 272 const std::string dictEntrySignature = signature_of<_Key>::str() + signature_of<_Value>::str(); 273 const std::string arraySignature = "{" + dictEntrySignature + "}"; 274 275 msg.openContainer(arraySignature); 276 277 for (const auto& item : items) 278 { 279 msg.openDictEntry(dictEntrySignature); 280 msg << item.first; 281 msg << item.second; 282 msg.closeDictEntry(); 283 } 284 285 msg.closeContainer(); 286 287 return msg; 288 } 289 290 namespace detail 291 { 292 template <typename... _Args> serialize_pack(Message & msg,_Args &&...args)293 void serialize_pack(Message& msg, _Args&&... args) 294 { 295 (void)(msg << ... << args); 296 } 297 298 template <class _Tuple, std::size_t... _Is> serialize_tuple(Message & msg,const _Tuple & t,std::index_sequence<_Is...>)299 void serialize_tuple( Message& msg 300 , const _Tuple& t 301 , std::index_sequence<_Is...>) 302 { 303 serialize_pack(msg, std::get<_Is>(t)...); 304 } 305 } 306 307 template <typename... _ValueTypes> 308 inline Message& operator<<(Message& msg, const Struct<_ValueTypes...>& item) 309 { 310 auto structSignature = signature_of<Struct<_ValueTypes...>>::str(); 311 assert(structSignature.size() > 2); 312 // Remove opening and closing parenthesis from the struct signature to get contents signature 313 auto structContentSignature = structSignature.substr(1, structSignature.size()-2); 314 315 msg.openStruct(structContentSignature); 316 detail::serialize_tuple(msg, item, std::index_sequence_for<_ValueTypes...>{}); 317 msg.closeStruct(); 318 319 return msg; 320 } 321 322 template <typename... _ValueTypes> 323 inline Message& operator<<(Message& msg, const std::tuple<_ValueTypes...>& item) 324 { 325 detail::serialize_tuple(msg, item, std::index_sequence_for<_ValueTypes...>{}); 326 return msg; 327 } 328 329 330 template <typename _Element> 331 inline Message& operator>>(Message& msg, std::vector<_Element>& items) 332 { 333 if(!msg.enterContainer(signature_of<_Element>::str())) 334 return msg; 335 336 while (true) 337 { 338 _Element elem; 339 if (msg >> elem) 340 items.emplace_back(std::move(elem)); 341 else 342 break; 343 } 344 345 msg.clearFlags(); 346 347 msg.exitContainer(); 348 349 return msg; 350 } 351 352 template <typename _Key, typename _Value> 353 inline Message& operator>>(Message& msg, std::map<_Key, _Value>& items) 354 { 355 const std::string dictEntrySignature = signature_of<_Key>::str() + signature_of<_Value>::str(); 356 const std::string arraySignature = "{" + dictEntrySignature + "}"; 357 358 if (!msg.enterContainer(arraySignature)) 359 return msg; 360 361 while (true) 362 { 363 if (!msg.enterDictEntry(dictEntrySignature)) 364 break; 365 366 _Key key; 367 _Value value; 368 msg >> key >> value; 369 370 items.emplace(std::move(key), std::move(value)); 371 372 msg.exitDictEntry(); 373 } 374 375 msg.clearFlags(); 376 377 msg.exitContainer(); 378 379 return msg; 380 } 381 382 namespace detail 383 { 384 template <typename... _Args> deserialize_pack(Message & msg,_Args &...args)385 void deserialize_pack(Message& msg, _Args&... args) 386 { 387 (void)(msg >> ... >> args); 388 } 389 390 template <class _Tuple, std::size_t... _Is> deserialize_tuple(Message & msg,_Tuple & t,std::index_sequence<_Is...>)391 void deserialize_tuple( Message& msg 392 , _Tuple& t 393 , std::index_sequence<_Is...> ) 394 { 395 deserialize_pack(msg, std::get<_Is>(t)...); 396 } 397 } 398 399 template <typename... _ValueTypes> 400 inline Message& operator>>(Message& msg, Struct<_ValueTypes...>& item) 401 { 402 auto structSignature = signature_of<Struct<_ValueTypes...>>::str(); 403 // Remove opening and closing parenthesis from the struct signature to get contents signature 404 auto structContentSignature = structSignature.substr(1, structSignature.size()-2); 405 406 if (!msg.enterStruct(structContentSignature)) 407 return msg; 408 409 detail::deserialize_tuple(msg, item, std::index_sequence_for<_ValueTypes...>{}); 410 411 msg.exitStruct(); 412 413 return msg; 414 } 415 416 template <typename... _ValueTypes> 417 inline Message& operator>>(Message& msg, std::tuple<_ValueTypes...>& item) 418 { 419 detail::deserialize_tuple(msg, item, std::index_sequence_for<_ValueTypes...>{}); 420 return msg; 421 } 422 423 } 424 425 #endif /* SDBUS_CXX_MESSAGE_H_ */ 426