summaryrefslogtreecommitdiffstats
path: root/toolkit/components/remote/nsDBusRemoteClient.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--toolkit/components/remote/nsDBusRemoteClient.cpp188
1 files changed, 188 insertions, 0 deletions
diff --git a/toolkit/components/remote/nsDBusRemoteClient.cpp b/toolkit/components/remote/nsDBusRemoteClient.cpp
new file mode 100644
index 0000000000..69e8d07c72
--- /dev/null
+++ b/toolkit/components/remote/nsDBusRemoteClient.cpp
@@ -0,0 +1,188 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:expandtab:shiftwidth=2:tabstop=8:
+ */
+/* vim:set ts=8 sw=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsDBusRemoteClient.h"
+#include "RemoteUtils.h"
+#include "mozilla/XREAppData.h"
+#include "mozilla/Logging.h"
+#include "mozilla/Base64.h"
+#include "nsPrintfCString.h"
+
+#include <dlfcn.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#undef LOG
+#ifdef MOZ_LOGGING
+static mozilla::LazyLogModule sRemoteLm("nsDBusRemoteClient");
+# define LOG(str, ...) \
+ MOZ_LOG(sRemoteLm, mozilla::LogLevel::Debug, (str, ##__VA_ARGS__))
+#else
+# define LOG(...)
+#endif
+
+nsDBusRemoteClient::nsDBusRemoteClient() {
+ mConnection = nullptr;
+ LOG("nsDBusRemoteClient::nsDBusRemoteClient");
+}
+
+nsDBusRemoteClient::~nsDBusRemoteClient() {
+ LOG("nsDBusRemoteClient::~nsDBusRemoteClient");
+ Shutdown();
+}
+
+nsresult nsDBusRemoteClient::Init() {
+ LOG("nsDBusRemoteClient::Init");
+
+ if (mConnection) return NS_OK;
+
+ mConnection =
+ already_AddRefed<DBusConnection>(dbus_bus_get(DBUS_BUS_SESSION, nullptr));
+ if (!mConnection) {
+ LOG(" failed to get DBus session");
+ return NS_ERROR_FAILURE;
+ }
+
+ dbus_connection_set_exit_on_disconnect(mConnection, false);
+ dbus_connection_setup_with_g_main(mConnection, nullptr);
+
+ return NS_OK;
+}
+
+void nsDBusRemoteClient::Shutdown(void) {
+ LOG("nsDBusRemoteClient::Shutdown");
+ // This connection is owned by libdbus and we don't need to close it
+ mConnection = nullptr;
+}
+
+nsresult nsDBusRemoteClient::SendCommandLine(
+ const char* aProgram, const char* aProfile, int32_t argc, char** argv,
+ const char* aStartupToken, char** aResponse, bool* aWindowFound) {
+ NS_ENSURE_TRUE(aProgram, NS_ERROR_INVALID_ARG);
+
+ LOG("nsDBusRemoteClient::SendCommandLine");
+
+ int commandLineLength;
+ char* commandLine =
+ ConstructCommandLine(argc, argv, aStartupToken, &commandLineLength);
+ if (!commandLine) {
+ LOG(" failed to create command line");
+ return NS_ERROR_FAILURE;
+ }
+
+ nsresult rv =
+ DoSendDBusCommandLine(aProgram, aProfile, commandLine, commandLineLength);
+ free(commandLine);
+
+ *aWindowFound = NS_SUCCEEDED(rv);
+
+ LOG("DoSendDBusCommandLine %s", NS_SUCCEEDED(rv) ? "OK" : "FAILED");
+ return rv;
+}
+
+bool nsDBusRemoteClient::GetRemoteDestinationName(const char* aProgram,
+ const char* aProfile,
+ nsCString& aDestinationName) {
+ // We have a profile name - just create the destination.
+ // D-Bus names can contain only [a-z][A-Z][0-9]_
+ // characters so adjust the profile string properly.
+ nsAutoCString profileName;
+ nsresult rv = mozilla::Base64Encode(nsAutoCString(aProfile), profileName);
+ NS_ENSURE_SUCCESS(rv, false);
+
+ mozilla::XREAppData::SanitizeNameForDBus(profileName);
+
+ aDestinationName =
+ nsPrintfCString("org.mozilla.%s.%s", aProgram, profileName.get());
+ if (aDestinationName.Length() > DBUS_MAXIMUM_NAME_LENGTH)
+ aDestinationName.Truncate(DBUS_MAXIMUM_NAME_LENGTH);
+
+ static auto sDBusValidateBusName = (bool (*)(const char*, DBusError*))dlsym(
+ RTLD_DEFAULT, "dbus_validate_bus_name");
+ if (!sDBusValidateBusName) {
+ LOG(" failed to get dbus_validate_bus_name()");
+ return false;
+ }
+
+ if (!sDBusValidateBusName(aDestinationName.get(), nullptr)) {
+ // We don't have a valid busName yet - try to create a default one.
+ aDestinationName =
+ nsPrintfCString("org.mozilla.%s.%s", aProgram, "default");
+ if (!sDBusValidateBusName(aDestinationName.get(), nullptr)) {
+ // We failed completelly to get a valid bus name - just quit
+ // to prevent crash at dbus_bus_request_name().
+ LOG(" failed to validate profile DBus name");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+nsresult nsDBusRemoteClient::DoSendDBusCommandLine(const char* aProgram,
+ const char* aProfile,
+ const char* aBuffer,
+ int aLength) {
+ LOG("nsDBusRemoteClient::DoSendDBusCommandLine()");
+
+ nsAutoCString appName(aProgram);
+ mozilla::XREAppData::SanitizeNameForDBus(appName);
+
+ nsAutoCString destinationName;
+ if (!GetRemoteDestinationName(appName.get(), aProfile, destinationName)) {
+ LOG(" failed to get remote destination name");
+ return NS_ERROR_FAILURE;
+ }
+
+ nsAutoCString pathName;
+ pathName = nsPrintfCString("/org/mozilla/%s/Remote", appName.get());
+
+ static auto sDBusValidatePathName = (bool (*)(const char*, DBusError*))dlsym(
+ RTLD_DEFAULT, "dbus_validate_path");
+ if (!sDBusValidatePathName ||
+ !sDBusValidatePathName(pathName.get(), nullptr)) {
+ LOG(" failed to validate path name");
+ return NS_ERROR_FAILURE;
+ }
+
+ nsAutoCString remoteInterfaceName;
+ remoteInterfaceName = nsPrintfCString("org.mozilla.%s", appName.get());
+
+ LOG(" DBus destination: %s\n", destinationName.get());
+ LOG(" DBus path: %s\n", pathName.get());
+ LOG(" DBus interface: %s\n", remoteInterfaceName.get());
+
+ RefPtr<DBusMessage> msg =
+ already_AddRefed<DBusMessage>(dbus_message_new_method_call(
+ destinationName.get(),
+ pathName.get(), // object to call on
+ remoteInterfaceName.get(), // interface to call on
+ "OpenURL")); // method name
+ if (!msg) {
+ LOG(" failed to create DBus message");
+ return NS_ERROR_FAILURE;
+ }
+
+ // append arguments
+ if (!dbus_message_append_args(msg, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &aBuffer,
+ aLength, DBUS_TYPE_INVALID)) {
+ LOG(" failed to create DBus message");
+ return NS_ERROR_FAILURE;
+ }
+
+ // send message and get a handle for a reply
+ RefPtr<DBusMessage> reply = already_AddRefed<DBusMessage>(
+ dbus_connection_send_with_reply_and_block(mConnection, msg, -1, nullptr));
+
+#ifdef MOZ_LOGGING
+ if (!reply) {
+ LOG(" failed to get DBus reply");
+ }
+#endif
+
+ return reply ? NS_OK : NS_ERROR_FAILURE;
+}