diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /toolkit/components/remote/nsDBusRemoteServer.cpp | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'toolkit/components/remote/nsDBusRemoteServer.cpp')
-rw-r--r-- | toolkit/components/remote/nsDBusRemoteServer.cpp | 214 |
1 files changed, 214 insertions, 0 deletions
diff --git a/toolkit/components/remote/nsDBusRemoteServer.cpp b/toolkit/components/remote/nsDBusRemoteServer.cpp new file mode 100644 index 0000000000..34167177d9 --- /dev/null +++ b/toolkit/components/remote/nsDBusRemoteServer.cpp @@ -0,0 +1,214 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:expandtab:shiftwidth=2:tabstop=2: + */ +/* 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 "nsDBusRemoteServer.h" + +#include "nsCOMPtr.h" +#include "mozilla/XREAppData.h" +#include "mozilla/Base64.h" +#include "mozilla/ScopeExit.h" +#include "nsPrintfCString.h" + +#include "nsGTKToolkit.h" + +#include <dbus/dbus.h> +#include <dbus/dbus-glib-lowlevel.h> + +#include <dlfcn.h> + +static const char* introspect_template = + "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection " + "1.0//EN\"\n" + "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n" + "<node>\n" + " <interface name=\"org.freedesktop.DBus.Introspectable\">\n" + " <method name=\"Introspect\">\n" + " <arg name=\"data\" direction=\"out\" type=\"s\"/>\n" + " </method>\n" + " </interface>\n" + " <interface name=\"org.mozilla.%s\">\n" + " <method name=\"OpenURL\">\n" + " <arg name=\"url\" direction=\"in\" type=\"ay\"/>\n" + " </method>\n" + " </interface>\n" + "</node>\n"; + +DBusHandlerResult nsDBusRemoteServer::Introspect(DBusMessage* msg) { + DBusMessage* reply = dbus_message_new_method_return(msg); + if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; + + nsAutoCString introspect_xml; + introspect_xml = nsPrintfCString(introspect_template, mAppName.get()); + + const char* message = introspect_xml.get(); + dbus_message_append_args(reply, DBUS_TYPE_STRING, &message, + DBUS_TYPE_INVALID); + + dbus_connection_send(mConnection, reply, nullptr); + dbus_message_unref(reply); + + return DBUS_HANDLER_RESULT_HANDLED; +} + +DBusHandlerResult nsDBusRemoteServer::OpenURL(DBusMessage* msg) { + DBusMessage* reply = nullptr; + const char* commandLine; + int length; + + if (!dbus_message_get_args(msg, nullptr, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, + &commandLine, &length, DBUS_TYPE_INVALID) || + length == 0) { + nsAutoCString errorMsg; + errorMsg = nsPrintfCString("org.mozilla.%s.Error", mAppName.get()); + reply = dbus_message_new_error(msg, errorMsg.get(), "Wrong argument"); + } else { + guint32 timestamp = gtk_get_current_event_time(); + if (timestamp == GDK_CURRENT_TIME) { + timestamp = guint32(g_get_monotonic_time() / 1000); + } + HandleCommandLine(commandLine, timestamp); + reply = dbus_message_new_method_return(msg); + } + + dbus_connection_send(mConnection, reply, nullptr); + dbus_message_unref(reply); + + return DBUS_HANDLER_RESULT_HANDLED; +} + +DBusHandlerResult nsDBusRemoteServer::HandleDBusMessage( + DBusConnection* aConnection, DBusMessage* msg) { + NS_ASSERTION(mConnection == aConnection, "Wrong D-Bus connection."); + + const char* method = dbus_message_get_member(msg); + const char* iface = dbus_message_get_interface(msg); + + if ((strcmp("Introspect", method) == 0) && + (strcmp("org.freedesktop.DBus.Introspectable", iface) == 0)) { + return Introspect(msg); + } + + nsAutoCString ourInterfaceName; + ourInterfaceName = nsPrintfCString("org.mozilla.%s", mAppName.get()); + + if ((strcmp("OpenURL", method) == 0) && + (strcmp(ourInterfaceName.get(), iface) == 0)) { + return OpenURL(msg); + } + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +void nsDBusRemoteServer::UnregisterDBusInterface(DBusConnection* aConnection) { + NS_ASSERTION(mConnection == aConnection, "Wrong D-Bus connection."); + // Not implemented +} + +static DBusHandlerResult message_handler(DBusConnection* conn, DBusMessage* msg, + void* user_data) { + auto interface = static_cast<nsDBusRemoteServer*>(user_data); + return interface->HandleDBusMessage(conn, msg); +} + +static void unregister(DBusConnection* conn, void* user_data) { + auto interface = static_cast<nsDBusRemoteServer*>(user_data); + interface->UnregisterDBusInterface(conn); +} + +static DBusObjectPathVTable remoteHandlersTable = { + .unregister_function = unregister, + .message_function = message_handler, +}; + +nsresult nsDBusRemoteServer::Startup(const char* aAppName, + const char* aProfileName) { + if (mConnection && dbus_connection_get_is_connected(mConnection)) { + // We're already connected so we don't need to reconnect + return NS_ERROR_ALREADY_INITIALIZED; + } + + // Don't even try to start without any application/profile name + if (!aAppName || aAppName[0] == '\0' || !aProfileName || + aProfileName[0] == '\0') + return NS_ERROR_INVALID_ARG; + + mConnection = dont_AddRef(dbus_bus_get(DBUS_BUS_SESSION, nullptr)); + if (!mConnection) { + return NS_ERROR_FAILURE; + } + auto releaseDBusConnection = + mozilla::MakeScopeExit([&] { mConnection = nullptr; }); + dbus_connection_set_exit_on_disconnect(mConnection, false); + dbus_connection_setup_with_g_main(mConnection, nullptr); + + mAppName = aAppName; + mozilla::XREAppData::SanitizeNameForDBus(mAppName); + + nsAutoCString profileName; + MOZ_TRY( + mozilla::Base64Encode(aProfileName, strlen(aProfileName), profileName)); + + mozilla::XREAppData::SanitizeNameForDBus(profileName); + + nsPrintfCString busName("org.mozilla.%s.%s", mAppName.get(), + profileName.get()); + if (busName.Length() > DBUS_MAXIMUM_NAME_LENGTH) + busName.Truncate(DBUS_MAXIMUM_NAME_LENGTH); + + static auto sDBusValidateBusName = (bool (*)(const char*, DBusError*))dlsym( + RTLD_DEFAULT, "dbus_validate_bus_name"); + if (!sDBusValidateBusName) { + return NS_ERROR_FAILURE; + } + + // We don't have a valid busName yet - try to create a default one. + if (!sDBusValidateBusName(busName.get(), nullptr)) { + busName = nsPrintfCString("org.mozilla.%s.%s", mAppName.get(), "default"); + if (!sDBusValidateBusName(busName.get(), nullptr)) { + // We failed completelly to get a valid bus name - just quit + // to prevent crash at dbus_bus_request_name(). + return NS_ERROR_FAILURE; + } + } + + DBusError err; + dbus_error_init(&err); + dbus_bus_request_name(mConnection, busName.get(), DBUS_NAME_FLAG_DO_NOT_QUEUE, + &err); + // The interface is already owned - there is another application/profile + // instance already running. + if (dbus_error_is_set(&err)) { + dbus_error_free(&err); + return NS_ERROR_FAILURE; + } + + mPathName = nsPrintfCString("/org/mozilla/%s/Remote", mAppName.get()); + static auto sDBusValidatePathName = (bool (*)(const char*, DBusError*))dlsym( + RTLD_DEFAULT, "dbus_validate_path"); + if (!sDBusValidatePathName || + !sDBusValidatePathName(mPathName.get(), nullptr)) { + return NS_ERROR_FAILURE; + } + if (!dbus_connection_register_object_path(mConnection, mPathName.get(), + &remoteHandlersTable, this)) { + return NS_ERROR_FAILURE; + } + + releaseDBusConnection.release(); + return NS_OK; +} + +void nsDBusRemoteServer::Shutdown() { + if (!mConnection) { + return; + } + + dbus_connection_unregister_object_path(mConnection, mPathName.get()); + + // dbus_connection_unref() will be called by RefPtr here. + mConnection = nullptr; +} |