]> code.delx.au - pulseaudio/blob - src/daemon/server-lookup.c
7c80d677e3faee6dad8d2ab33bad29a3cbc7f7d6
[pulseaudio] / src / daemon / server-lookup.c
1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2009 Tanu Kaskinen
5
6 PulseAudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published
8 by the Free Software Foundation; either version 2.1 of the License,
9 or (at your option) any later version.
10
11 PulseAudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with PulseAudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <dbus/dbus.h>
27
28 #include <pulse/client-conf.h>
29 #include <pulse/xmalloc.h>
30
31 #include <pulsecore/core.h>
32 #include <pulsecore/core-util.h>
33 #include <pulsecore/dbus-common.h>
34 #include <pulsecore/dbus-shared.h>
35 #include <pulsecore/macro.h>
36
37 #include "server-lookup.h"
38
39 #define OBJECT_PATH "/org/pulseaudio1/server_lookup"
40 #define INTERFACE "org.pulseaudio.ServerLookup1"
41
42 struct pa_dbusobj_server_lookup {
43 pa_core *core;
44 pa_dbus_connection *conn;
45 pa_bool_t path_registered;
46 };
47
48 static const char introspection[] =
49 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
50 "<node>"
51 " <!-- If you are looking for documentation make sure to check out\n"
52 " http://pulseaudio.org/wiki/DBusInterface -->\n"
53 " <interface name=\"" INTERFACE "\">"
54 " <method name=\"GetAddress\">"
55 " <arg name=\"result\" type=\"s\" direction=\"out\"/>"
56 " </method>"
57 " </interface>"
58 " <interface name=\"org.freedesktop.DBus.Introspectable\">"
59 " <method name=\"Introspect\">"
60 " <arg name=\"data\" type=\"s\" direction=\"out\"/>"
61 " </method>"
62 " </interface>"
63 "</node>";
64
65 static void unregister_cb(DBusConnection *conn, void *user_data) {
66 pa_dbusobj_server_lookup *sl = user_data;
67
68 pa_assert(sl);
69 pa_assert(sl->path_registered);
70
71 sl->path_registered = FALSE;
72 }
73
74 static DBusHandlerResult handle_introspect(DBusConnection *conn, DBusMessage *msg, pa_dbusobj_server_lookup *sl) {
75 const char *i = introspection;
76 DBusMessage *reply = NULL;
77
78 pa_assert(conn);
79 pa_assert(msg);
80
81 if (!(reply = dbus_message_new_method_return(msg)))
82 goto fail;
83
84 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &i, DBUS_TYPE_INVALID))
85 goto fail;
86
87 if (!dbus_connection_send(conn, reply, NULL))
88 goto oom;
89
90 dbus_message_unref(reply);
91
92 return DBUS_HANDLER_RESULT_HANDLED;
93
94 fail:
95 if (reply)
96 dbus_message_unref(reply);
97
98 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
99
100 oom:
101 if (reply)
102 dbus_message_unref(reply);
103
104 return DBUS_HANDLER_RESULT_NEED_MEMORY;
105 }
106
107 static DBusHandlerResult handle_get_address(DBusConnection *conn, DBusMessage *msg, pa_dbusobj_server_lookup *sl) {
108 DBusMessage *reply = NULL;
109 pa_client_conf *conf = NULL;
110 char *address = NULL;
111
112 pa_assert(conn);
113 pa_assert(msg);
114 pa_assert(sl);
115
116 conf = pa_client_conf_new();
117
118 if (pa_client_conf_load(conf, NULL) < 0) {
119 if (!(reply = dbus_message_new_error(msg, "org.pulseaudio.ClientConfLoadError", "Failed to load client.conf.")))
120 goto fail;
121 if (!dbus_connection_send(conn, reply, NULL))
122 goto oom;
123 return DBUS_HANDLER_RESULT_HANDLED;
124 }
125
126 if (conf->default_dbus_server) {
127 address = pa_xstrdup(conf->default_dbus_server);
128 } else {
129 if (!(address = pa_get_dbus_address_from_server_type(sl->core->server_type))) {
130 if (!(reply = dbus_message_new_error(msg, DBUS_ERROR_FAILED, "PulseAudio internal error: get_dbus_server_from_type() failed.")))
131 goto fail;
132 if (!dbus_connection_send(conn, reply, NULL))
133 goto oom;
134 return DBUS_HANDLER_RESULT_HANDLED;
135 }
136 }
137
138 if (!(reply = dbus_message_new_method_return(msg)))
139 goto oom;
140
141 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &address, DBUS_TYPE_INVALID))
142 goto fail;
143
144 if (!dbus_connection_send(conn, reply, NULL))
145 goto oom;
146
147 pa_client_conf_free(conf);
148 pa_xfree(address);
149 dbus_message_unref(reply);
150
151 return DBUS_HANDLER_RESULT_HANDLED;
152
153 fail:
154 if (conf)
155 pa_client_conf_free(conf);
156
157 pa_xfree(address);
158
159 if (reply)
160 dbus_message_unref(reply);
161
162 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
163
164 oom:
165 if (conf)
166 pa_client_conf_free(conf);
167
168 pa_xfree(address);
169
170 if (reply)
171 dbus_message_unref(reply);
172
173 return DBUS_HANDLER_RESULT_NEED_MEMORY;
174 }
175
176 static DBusHandlerResult message_cb(DBusConnection *conn, DBusMessage *msg, void *user_data) {
177 pa_dbusobj_server_lookup *sl = user_data;
178
179 pa_assert(conn);
180 pa_assert(msg);
181 pa_assert(sl);
182
183 /* pa_log("Got message! type = %s path = %s iface = %s member = %s dest = %s", dbus_message_type_to_string(dbus_message_get_type(msg)), dbus_message_get_path(msg), dbus_message_get_interface(msg), dbus_message_get_member(msg), dbus_message_get_destination(msg)); */
184
185 if (dbus_message_is_method_call(msg, "org.freedesktop.DBus.Introspectable", "Introspect"))
186 return handle_introspect(conn, msg, sl);
187
188 if (dbus_message_is_method_call(msg, INTERFACE, "GetAddress"))
189 return handle_get_address(conn, msg, sl);
190
191 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
192 }
193
194 static DBusObjectPathVTable vtable = {
195 .unregister_function = unregister_cb,
196 .message_function = message_cb,
197 .dbus_internal_pad1 = NULL,
198 .dbus_internal_pad2 = NULL,
199 .dbus_internal_pad3 = NULL,
200 .dbus_internal_pad4 = NULL
201 };
202
203 pa_dbusobj_server_lookup *pa_dbusobj_server_lookup_new(pa_core *c) {
204 pa_dbusobj_server_lookup *sl;
205 DBusError error;
206
207 dbus_error_init(&error);
208
209 sl = pa_xnew(pa_dbusobj_server_lookup, 1);
210 sl->core = c;
211 sl->path_registered = FALSE;
212
213 if (!(sl->conn = pa_dbus_bus_get(c, DBUS_BUS_SESSION, &error)) || dbus_error_is_set(&error)) {
214 pa_log("Unable to contact D-Bus: %s: %s", error.name, error.message);
215 goto fail;
216 }
217
218 if (!dbus_connection_register_object_path(pa_dbus_connection_get(sl->conn), OBJECT_PATH, &vtable, sl)) {
219 pa_log("dbus_connection_register_object_path() failed for " OBJECT_PATH ".");
220 goto fail;
221 }
222
223 sl->path_registered = TRUE;
224
225 return sl;
226
227 fail:
228 dbus_error_free(&error);
229
230 pa_dbusobj_server_lookup_free(sl);
231
232 return NULL;
233 }
234
235 void pa_dbusobj_server_lookup_free(pa_dbusobj_server_lookup *sl) {
236 pa_assert(sl);
237
238 if (sl->path_registered) {
239 pa_assert(sl->conn);
240 if (!dbus_connection_unregister_object_path(pa_dbus_connection_get(sl->conn), OBJECT_PATH))
241 pa_log_debug("dbus_connection_unregister_object_path() failed for " OBJECT_PATH ".");
242 }
243
244 if (sl->conn)
245 pa_dbus_connection_unref(sl->conn);
246
247 pa_xfree(sl);
248 }