8 #include "../message.h" 17 #include <dbus/dbus-protocol.h> 18 #include <dbus/dbus.h> 19 #include "../../macros.h" 20 #include "../../misc.h" 21 #include "../../unixfd.h" 22 #include "../variant.h" 24 #include "message_p.h" 28 static char toDBusType(Container::Type type) {
31 case Container::Type::Array:
34 case Container::Type::DictEntry:
35 t = DBUS_TYPE_DICT_ENTRY;
37 case Container::Type::Struct:
40 case Container::Type::Variant:
41 t = DBUS_TYPE_VARIANT;
44 throw std::runtime_error(
"invalid container type");
49 Message::Message() : d_ptr(
std::make_unique<MessagePrivate>()) {}
51 FCITX_DEFINE_DEFAULT_DTOR_AND_MOVE(Message)
55 auto *dmsg = dbus_message_new_method_return(d->msg());
59 return MessagePrivate::fromDBusMessage(d->bus_, dmsg,
true,
false);
64 auto *dmsg = dbus_message_new_error(d->msg(), name, message);
68 return MessagePrivate::fromDBusMessage(d->bus_, dmsg,
false,
false);
79 dbus_message_set_destination(d->msg(), dest.c_str());
88 const auto *result = dbus_message_get_destination(d->msg());
89 return result ? result :
"";
97 const auto *sender = dbus_message_get_sender(d->msg());
98 return sender ? sender :
"";
106 const auto *member = dbus_message_get_member(d->msg());
107 return member ? member :
"";
115 const auto *
interface = dbus_message_get_interface(d->msg());
116 return interface ? interface : "";
124 const auto *signature = dbus_message_get_signature(d->msg());
125 return signature ? signature :
"";
130 const auto *path = dbus_message_get_path(d->msg());
131 return path ? path :
"";
137 const auto *err = dbus_message_get_error_name(d->msg());
138 return err ? err :
"";
146 char *message =
nullptr;
147 if (dbus_message_get_args(d->msg(),
nullptr, DBUS_TYPE_STRING, &message,
148 DBUS_TYPE_INVALID)) {
161 int convertTimeout(uint64_t timeout) {
162 int milliTimout = timeout / 1000;
163 if (timeout > 0 && milliTimout == 0) {
165 }
else if (timeout == 0) {
166 milliTimout = DBUS_TIMEOUT_USE_DEFAULT;
173 ScopedDBusError error;
174 auto *bus = d->bus_.get();
178 DBusMessage *reply = dbus_connection_send_with_reply_and_block(
179 bus->conn_.get(), d->msg(), convertTimeout(usec), &error.error());
181 return MessagePrivate::fromDBusError(error.error());
183 return MessagePrivate::fromDBusMessage(bus->watch(), reply,
false,
false);
186 void DBusPendingCallNotifyCallback(DBusPendingCall *reply,
void *userdata) {
187 auto *slot =
static_cast<DBusAsyncCallSlot *
>(userdata);
192 auto msg = MessagePrivate::fromDBusMessage(
193 slot->bus_, dbus_pending_call_steal_reply(reply),
false,
false);
194 slot->callback_(msg);
198 MessageCallback callback) {
200 auto *bus = d->bus_.get();
204 auto slot = std::make_unique<DBusAsyncCallSlot>(std::move(callback));
205 DBusPendingCall *call =
nullptr;
206 if (!dbus_connection_send_with_reply(bus->conn_.get(), d->msg(), &call,
207 convertTimeout(usec))) {
211 dbus_pending_call_set_notify(call, DBusPendingCallNotifyCallback,
212 slot.get(),
nullptr);
214 slot->bus_ = bus->watch();
219 Message::operator bool()
const {
221 return d->msg() && d->lastError_ >= 0;
241 dbus_message_iter_next(d->iterator());
244 uint64_t Message::serial() {
249 return dbus_message_get_serial(d->msg());
252 uint64_t Message::replySerial() {
257 return dbus_message_get_reply_serial(d->msg());
263 UniqueCPtr<char, dbus_free> content;
264 auto container = dbus_message_iter_get_arg_type(d->iterator());
265 if (container == DBUS_TYPE_ARRAY || container == DBUS_TYPE_STRUCT ||
266 container == DBUS_TYPE_VARIANT) {
267 auto *subIter = d->pushReadIterator();
268 content.reset(dbus_message_iter_get_signature(subIter));
272 return {container, content.get()};
274 return {container,
""};
279 auto *bus = d->bus_.get();
281 if (dbus_connection_send(bus->conn_.get(), d->msg(),
nullptr)) {
288 Message &Message::operator<<(
bool b) {
290 dbus_bool_t i = b ? 1 : 0;
292 dbus_message_iter_append_basic(d->iterator(), DBUS_TYPE_BOOLEAN, &i);
296 Message &Message::operator>>(
bool &b) {
299 if (dbus_message_iter_get_arg_type(d->iterator()) == DBUS_TYPE_BOOLEAN) {
300 dbus_message_iter_get_basic(d->iterator(), &i);
302 dbus_message_iter_next(d->iterator());
308 #define _MARSHALL_FUNC(TYPE, TYPE2) \ 309 Message &Message::operator<<(TYPE v) { \ 314 d->lastError_ = !dbus_message_iter_append_basic( \ 315 d->iterator(), DBUS_TYPE_##TYPE2, &v); \ 318 Message &Message::operator>>(TYPE &v) { \ 323 if (dbus_message_iter_get_arg_type(d->iterator()) == \ 324 DBUS_TYPE_##TYPE2) { \ 325 dbus_message_iter_get_basic(d->iterator(), &v); \ 326 dbus_message_iter_next(d->iterator()); \ 328 d->lastError_ = -EINVAL; \ 334 _MARSHALL_FUNC(uint8_t, BYTE)
335 _MARSHALL_FUNC(int16_t, INT16)
336 _MARSHALL_FUNC(uint16_t, UINT16)
337 _MARSHALL_FUNC(int32_t, INT32)
338 _MARSHALL_FUNC(uint32_t, UINT32)
339 _MARSHALL_FUNC(int64_t, INT64)
340 _MARSHALL_FUNC(uint64_t, UINT64)
341 _MARSHALL_FUNC(
double, DOUBLE)
343 Message &Message::operator<<(
const std::string &s) {
348 Message &Message::operator<<(
const char *s) {
354 !dbus_message_iter_append_basic(d->iterator(), DBUS_TYPE_STRING, &s);
358 Message &Message::operator>>(std::string &s) {
365 if (dbus_message_iter_get_arg_type(d->iterator()) == DBUS_TYPE_STRING) {
366 dbus_message_iter_get_basic(d->iterator(), &p);
368 dbus_message_iter_next(d->iterator());
370 d->lastError_ = -EINVAL;
380 const char *c = o.path().c_str();
381 d->lastError_ = !dbus_message_iter_append_basic(d->iterator(),
382 DBUS_TYPE_OBJECT_PATH, &c);
392 if (dbus_message_iter_get_arg_type(d->iterator()) == DBUS_TYPE_STRING) {
393 dbus_message_iter_get_basic(d->iterator(), &p);
395 dbus_message_iter_next(d->iterator());
397 d->lastError_ = -EINVAL;
407 const char *c = s.sig().c_str();
409 !dbus_message_iter_append_basic(d->iterator(), DBUS_TYPE_SIGNATURE, &c);
419 if (dbus_message_iter_get_arg_type(d->iterator()) == DBUS_TYPE_SIGNATURE) {
420 dbus_message_iter_get_basic(d->iterator(), &p);
422 dbus_message_iter_next(d->iterator());
424 d->lastError_ = -EINVAL;
436 dbus_message_iter_append_basic(d->iterator(), DBUS_TYPE_UNIX_FD, &f);
446 if (dbus_message_iter_get_arg_type(d->iterator()) == DBUS_TYPE_UNIX_FD) {
447 dbus_message_iter_get_basic(d->iterator(), &f);
449 dbus_message_iter_next(d->iterator());
451 d->lastError_ = -EINVAL;
461 d->pushWriteIterator(toDBusType(c.type()), c.content().sig());
471 if (dbus_message_iter_get_arg_type(d->iterator()) != toDBusType(c.type())) {
472 d->lastError_ = -EINVAL;
474 DBusMessageIter *subIter = d->pushReadIterator();
476 if (c.type() != Container::Type::DictEntry &&
477 c.type() != Container::Type::Struct) {
478 UniqueCPtr<char, dbus_free> content(
479 dbus_message_iter_get_signature(subIter));
480 if (!content || content.get() != c.content().sig()) {
481 d->lastError_ = -EINVAL;
503 dbus_message_iter_next(d->iterator());
511 if (*
this <<
Container(Container::Type::Variant,
513 v.writeToMessage(*
this);
529 auto type = peekType();
530 if (type.first !=
'v') {
531 d->lastError_ = -EINVAL;
534 if (
auto helper = lookupVariantType(type.second)) {
537 auto data = helper->copy(
nullptr);
538 helper->deserialize(*
this, data.get());
540 variant.setRawData(std::move(data), std::move(helper));
545 dbus_message_iter_next(d->iterator());
bool send()
Send this message.
Helper type for serialization, should not be used directly.
Class wrap around the unix fd.
std::string destination() const
Return the destination of the message.
Basic DBus type of a DBus message.
std::string path() const
Return the path of the message.
String like type object signature 'g'.
Message createError(const char *name, const char *message) const
Create a error reply to this message.
void rewind()
Rewind the message to the beginning.
Helper type for serialization, should not be used directly.
std::string sender() const
Return the sender of the message.
MessageType type() const
Return the message type.
void * nativeHandle() const
Return the low level internal pointer of the message.
std::string member() const
Return the member of the message.
std::pair< char, std::string > peekType()
Check the next type of data in the message.
std::string interface() const
Return the interface of the message.
int fd() const noexcept
Get the internal fd.
void setDestination(const std::string &dest)
Set the destination of the message.
const std::string & signature() const
Return the signature of the data.
std::string errorMessage() const
Return the error message of the message.
Message call(uint64_t usec)
Synchronously call a dbus method with a timeout in microseconds.
void skip()
Skip the next data.
Variant type to be used to box or unbox the dbus variant type.
String like type object path 'o'.
void give(int fd) noexcept
Set a new FD and transfer the ownership to UnixFD.
std::string signature() const
Return the signature of the message.
bool end() const
Check if message reaches end.
void resetError()
Clear serialization error.
std::unique_ptr< Slot > callAsync(uint64_t usec, MessageCallback callback)
Asynchronously call a dbus method with a timeout in microseconds.
std::string errorName() const
Return the error name of the message.