From 802dc610328f3b6887cca1a5364c98248e043818 Mon Sep 17 00:00:00 2001 From: Benjamin Reed Date: Mon, 28 Jan 2008 13:11:13 -0500 Subject: [PATCH] Launchd support for Mac OS X (and potentially other platforms) Add support for launchd (http://developer.apple.com/macosx/launchd.html) Launchd is superficially like inetd in that it controls all resources for system-wide and session-level daemons. In the case of this dbus implementation, launchd allocates and listens on a socket, dynamically launching dbus when a client tries to access the socket for the first time. When dbus-daemon is started, it asks launchd for the socket file descriptor, and then initializes itself using that pre-existing FD. Note that this only occurs if in session.conf is set to "autolaunch:" -- it is still possible to us DBus on Mac OS X in the normal UNIXy way by specifying a tcp: or unix: session address. From the client-side, this code will do a number of things to attempt to auto-determine the socket. If DBUS_SESSION_BUS_ADDRESS is set, the client will connect normally, just like any other unix client. If it is not, it checks for the environment variable DBUS_LAUNCHD_SESSION_BUS_SOCKET and crafts a unix: socket URL from it. If that is not set, it asks launchd (through the 'launchctl' command) for the socket directly, and crafts a unix: socket URL from it instead. It then continues normally. Signed-off-by: Benjamin Reed --- bus/org.freedesktop.dbus-session.plist.in | 31 +++++++ dbus/dbus-server-launchd.c | 136 +++++++++++++++++++++++++++++ dbus/dbus-server-launchd.h | 35 ++++++++ 3 files changed, 202 insertions(+), 0 deletions(-) create mode 100644 bus/org.freedesktop.dbus-session.plist.in create mode 100644 dbus/dbus-server-launchd.c create mode 100644 dbus/dbus-server-launchd.h diff --git a/bus/org.freedesktop.dbus-session.plist.in b/bus/org.freedesktop.dbus-session.plist.in new file mode 100644 index 0000000..6f1ad8e --- /dev/null +++ b/bus/org.freedesktop.dbus-session.plist.in @@ -0,0 +1,31 @@ + + + + + Label + org.freedesktop.dbus-session + + ServiceIPC + + + + OnDemand + + + ProgramArguments + + @DBUS_DAEMONDIR@/dbus-daemon + --nofork + --session + + + Sockets + + session + + SecureSocketWithKey + DBUS_LAUNCHD_SESSION_BUS_SOCKET + + + + diff --git a/dbus/dbus-server-launchd.c b/dbus/dbus-server-launchd.c new file mode 100644 index 0000000..e5101f3 --- /dev/null +++ b/dbus/dbus-server-launchd.c @@ -0,0 +1,136 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-server-win.c Server implementation for WIN network protocols. + * + * Copyright (C) 2008 Benjamin Reed + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include + +#include "dbus-server-socket.h" +#include "dbus-server-launchd.h" + +/** + * @defgroup DBusServerLaunchd DBusServer implementations for Launchd + * @ingroup DBusInternals + * @brief Implementation details of DBusServer with Launchd support + * + * @{ + */ + +/** + * Creates a new server from launchd. + * + * @param socket_key they key to use when looking up the file descriptor from launchd + * @param error location to store reason for failure. + * @returns the new server, or #NULL on failure. + */ + +DBusServer* +_dbus_server_new_for_launchd_fd (const char *socket_key, DBusError *error) +{ + DBusServer *server; + DBusString address; + int launchd_fd; + launch_data_t sockets_dict, checkin_response; + launch_data_t checkin_request; + launch_data_t listening_fd_array, listening_fd; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + if (!_dbus_string_init (&address)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + return NULL; + } + if (!_dbus_string_append (&address, "autolaunch:key=")) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + goto l_failed_0; + } + if (!_dbus_string_append (&address, socket_key)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + goto l_failed_0; + } + + if ((checkin_request = launch_data_new_string(LAUNCH_KEY_CHECKIN)) == NULL) { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, "launch_data_new_string(\"%s\") Unable to create string.\n", LAUNCH_KEY_CHECKIN); + goto l_failed_0; + } + + if ((checkin_response = launch_msg(checkin_request)) == NULL) { + dbus_set_error (error, DBUS_ERROR_IO_ERROR, "launch_msg(\"%s\") IPC failure: %s\n", LAUNCH_KEY_CHECKIN, strerror(errno)); + goto l_failed_0; + } + + if (LAUNCH_DATA_ERRNO == launch_data_get_type(checkin_response)) { + dbus_set_error (error, DBUS_ERROR_FAILED, "Check-in failed: %s\n", strerror(launch_data_get_errno(checkin_response))); + goto l_failed_0; + } + + sockets_dict = launch_data_dict_lookup(checkin_response, LAUNCH_JOBKEY_SOCKETS); + if (NULL == sockets_dict) { + dbus_set_error (error, DBUS_ERROR_IO_ERROR, "No sockets found to answer requests on!\n"); + goto l_failed_0; + } + + listening_fd_array = launch_data_dict_lookup(sockets_dict, socket_key); + if (NULL == listening_fd_array) { + dbus_set_error (error, DBUS_ERROR_IO_ERROR, "No known sockets found to answer requests on!\n"); + goto l_failed_0; + } + + if (launch_data_array_get_count(listening_fd_array)!=1) { + dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED, "Expected 1 socket from launchd, got %d.\n", launch_data_array_get_count(listening_fd_array)); + goto l_failed_0; + } + + listening_fd=launch_data_array_get_index(listening_fd_array, 0); + launchd_fd=launch_data_get_fd(listening_fd); + + _dbus_fd_set_close_on_exec (launchd_fd); + + if (launchd_fd < 0) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + goto l_failed_0; + } + + server = _dbus_server_new_for_socket (&launchd_fd, 1, &address); + if (server == NULL) + { + dbus_set_error (error, DBUS_ERROR_NO_SERVER, "Unable to listen on launchd fd %d.", launchd_fd); + goto l_failed_0; + } + + _dbus_string_free (&address); + + return server; + + l_failed_0: + _dbus_string_free (&address); + + return NULL; +} + +/** @} */ + diff --git a/dbus/dbus-server-launchd.h b/dbus/dbus-server-launchd.h new file mode 100644 index 0000000..8719ecb --- /dev/null +++ b/dbus/dbus-server-launchd.h @@ -0,0 +1,35 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-server-launchd.h Server implementation for launchd integration. + * + * Copyright (C) 2008 Benjamin Reed + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#ifndef DBUS_SERVER_LAUNCHD_H +#define DBUS_SERVER_LAUNCHD_H + +#include +#include + +DBUS_BEGIN_DECLS + +DBusServer* _dbus_server_new_for_launchd_fd (const char *socket_fd, DBusError *error); + +DBUS_END_DECLS + +#endif /* DBUS_SERVER_LAUNCHD_H */ -- 1.5.3.7