diff --git a/applications/analyzer/eavesdropperthread.cpp b/applications/analyzer/eavesdropperthread.cpp index c6155f7..f5bea7a 100644 --- a/applications/analyzer/eavesdropperthread.cpp +++ b/applications/analyzer/eavesdropperthread.cpp @@ -1,96 +1,74 @@ /* Copyright (C) 2013 Andreas Hartmetz This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LGPL. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Alternatively, this file is available under the Mozilla Public License Version 1.1. You may obtain a copy of the License at http://www.mozilla.org/MPL/ */ #include "eavesdropperthread.h" #include "arguments.h" #include "connectaddress.h" #include "eavesdroppermodel.h" #include "error.h" #include "eventdispatcher.h" #include "localsocket.h" #include "message.h" +#include "pendingreply.h" #include "connection.h" +#include "../setupeavesdropping.h" + EavesdropperThread::EavesdropperThread(EavesdropperModel *model) { // do not parent this to the model; it doesn't work across threads moveToThread(&m_thread); connect(this, SIGNAL(messageReceived(Message *, qint64)), model, SLOT(addMessage(Message *, qint64)), Qt::QueuedConnection); connect(&m_thread, SIGNAL(started()), SLOT(run())); m_thread.start(); } EavesdropperThread::~EavesdropperThread() { m_dispatcher->interrupt(); m_thread.wait(); delete m_connection; delete m_dispatcher; } -static Message createEavesdropMessage(const char *messageType) -{ - Message ret = Message::createCall("/org/freedesktop/DBus", "org.freedesktop.DBus", "AddMatch"); - ret.setDestination("org.freedesktop.DBus"); - Arguments::Writer writer; - std::string str = "eavesdrop=true,type="; - str += messageType; - writer.writeString(cstring(str.c_str())); - ret.setArguments(writer.finish()); - return ret; -} - void EavesdropperThread::run() { m_timer.start(); m_dispatcher = new EventDispatcher; - m_connection = new Connection(m_dispatcher, ConnectAddress::StandardBus::Session); - m_connection->setSpontaneousMessageReceiver(this); - { - static const int messageTypeCount = 4; - const char *messageType[messageTypeCount] = { - "signal", - "method_call", - "method_return", - "error" - }; - for (int i = 0; i < messageTypeCount; i++) { - m_connection->sendNoReply(createEavesdropMessage(messageType[i])); - } - } - Q_ASSERT(m_connection->isConnected()); + setupEavesdropping(m_connection); + m_connection->setSpontaneousMessageReceiver(this); while (m_dispatcher->poll()) { } m_thread.quit(); } void EavesdropperThread::handleSpontaneousMessageReceived(Message message, Connection *) { emit messageReceived(new Message(std::move(message)), m_timer.nsecsElapsed()); } diff --git a/applications/dfer.cpp b/applications/dfer.cpp index f7e65d3..601b8b1 100644 --- a/applications/dfer.cpp +++ b/applications/dfer.cpp @@ -1,108 +1,92 @@ /* Copyright (C) 2013 Andreas Hartmetz This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LGPL. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Alternatively, this file is available under the Mozilla Public License Version 1.1. You may obtain a copy of the License at http://www.mozilla.org/MPL/ */ #include "arguments.h" #include "connectaddress.h" #include "error.h" #include "eventdispatcher.h" #include "imessagereceiver.h" #include "message.h" +#include "pendingreply.h" #include "connection.h" #include #include -static Message createEavesdropMessage(const char *messageType) -{ - Message ret = Message::createCall("/org/freedesktop/DBus", "org.freedesktop.DBus", "AddMatch"); - ret.setDestination("org.freedesktop.DBus"); - Arguments::Writer writer; - std::string str = "eavesdrop=true,type="; - str += messageType; - writer.writeString(cstring(str.c_str())); - ret.setArguments(writer.finish()); - return ret; -} +#include "setupeavesdropping.h" class ReplyPrinter : public IMessageReceiver { // reimplemented from IMessageReceiver void handleSpontaneousMessageReceived(Message m, Connection *) override; }; void ReplyPrinter::handleSpontaneousMessageReceived(Message m, Connection *) { std::cout << '\n' << m.prettyPrint(); } static void printHelp() { std::cout << "dfer options:\n" " --session-bus Monitor the session bus [the default]\n" " --system-bus Monitor the system bus\n" " --help Show this help and exit\n"; } int main(int argc, char *argv[]) { EventDispatcher dispatcher; ConnectAddress::StandardBus bus = ConnectAddress::StandardBus::Session; for (int i = 1; i < argc; i++) { std::string s = argv[i]; if (s == "--help") { printHelp(); exit(0); } else if (s == "--system-bus") { bus = ConnectAddress::StandardBus::System; } else if (s == "--session-bus") { bus = ConnectAddress::StandardBus::Session; } else { std::cerr << "Unknown option \"" << s << "\".\n"; printHelp(); exit(1); } } Connection connection(&dispatcher, bus); + + if (setupEavesdropping(&connection) == FailedEavesdropping) { + return -1; + } + ReplyPrinter receiver; connection.setSpontaneousMessageReceiver(&receiver); - { - static const int messageTypeCount = 4; - const char *messageType[messageTypeCount] = { - "signal", - "method_call", - "method_return", - "error" - }; - for (int i = 0; i < messageTypeCount; i++) { - connection.sendNoReply(createEavesdropMessage(messageType[i])); - } - } while (true) { dispatcher.poll(); } return 0; } diff --git a/applications/setupeavesdropping.h b/applications/setupeavesdropping.h new file mode 100644 index 0000000..4e4bb72 --- /dev/null +++ b/applications/setupeavesdropping.h @@ -0,0 +1,96 @@ +/* + Copyright (C) 2019 Andreas Hartmetz + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LGPL. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + Alternatively, this file is available under the Mozilla Public License + Version 1.1. You may obtain a copy of the License at + http://www.mozilla.org/MPL/ +*/ + +static Message createEavesdropMessage(const char *messageType) +{ + Message ret = Message::createCall("/org/freedesktop/DBus", "org.freedesktop.DBus", "AddMatch"); + ret.setDestination("org.freedesktop.DBus"); + Arguments::Writer writer; + std::string str = "eavesdrop=true,type="; + str += messageType; + writer.writeString(cstring(str.c_str())); + ret.setArguments(writer.finish()); + return ret; +} + +enum SetupEavesdroppingResult +{ + OldStyleEavesdropping = 0, + NewStyleEavesdropping, + FailedEavesdropping +}; + +static SetupEavesdroppingResult setupEavesdropping(Connection *connection) +{ + { + // new way to request eavesdropping / monitoring, not yet universally available + Message msg = Message::createCall("/org/freedesktop/DBus", "org.freedesktop.DBus.Monitoring", + "BecomeMonitor"); + msg.setDestination("org.freedesktop.DBus"); + Arguments::Writer writer; + writer.beginArray(Arguments::Writer::WriteTypesOfEmptyArray); + writer.writeString(cstring()); + writer.endArray(); + writer.writeUint32(0); + msg.setArguments(writer.finish()); + PendingReply pendingReply = connection->send(std::move(msg)); + while (!pendingReply.isFinished()) { + connection->eventDispatcher()->poll(); + } + if (!pendingReply.isError()) { + return NewStyleEavesdropping; + } + } + + { + // old way to request eavesdropping / monitoring, now disabled in some distributions + static const int messageTypeCount = 4; + const char *messageType[messageTypeCount] = { + "signal", + "method_call", + "method_return", + "error" + }; + + std::vector pendingReplies; + pendingReplies.reserve(messageTypeCount); + for (int i = 0; i < messageTypeCount; i++) { + pendingReplies.emplace_back(connection->send(createEavesdropMessage(messageType[i]))); + } + + bool done = false; + while (!done) { + connection->eventDispatcher()->poll(); + done = true; + for (const PendingReply &PR : pendingReplies) { + done = done && PR.isFinished(); + if (PR.isError()) { + // ### this error detection doesn't seem to work - on my test system with Kubuntu 19.10, + // eavesdropping failed silently(!) + return FailedEavesdropping; + } + } + } + } + return OldStyleEavesdropping; +}