git aware version script
[a2jmidid.git] / dbus.c
blob3f5b2ee6b4619b40a6603ecc3fac15eecca38002
1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
2 /*
3 * ALSA SEQ < - > JACK MIDI bridge
5 * Copyright (c) 2007,2008 Nedko Arnaudov <nedko@arnaudov.name>
6 * Copyright (C) 2007-2008 Juuso Alasuutari
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; version 2 of the License.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include <stdbool.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <dbus/dbus.h>
27 #include "dbus.h"
28 #include "log.h"
29 #include "dbus_internal.h"
30 #include "dbus_iface_control.h"
32 void
33 a2j_dbus_error(
34 void *dbus_call_context_ptr,
35 const char *error_name,
36 const char *format,
37 ...)
39 va_list ap;
40 char buffer[300];
42 va_start(ap, format);
44 vsnprintf(buffer, sizeof(buffer), format, ap);
46 a2j_error("%s", buffer);
47 if (dbus_call_context_ptr != NULL)
49 ((struct a2j_dbus_method_call *)dbus_call_context_ptr)->reply = dbus_message_new_error(
50 ((struct a2j_dbus_method_call *)dbus_call_context_ptr)->message,
51 error_name,
52 buffer);
55 va_end(ap);
59 * Send a method return.
61 * If call->reply is NULL (i.e. a message construct method failed
62 * due to lack of memory) attempt to send a void method return.
64 static
65 void
66 a2j_dbus_send_method_return(
67 struct a2j_dbus_method_call * call)
69 if (call->reply == NULL)
71 a2j_debug("send_method_return() called with a NULL message, trying to construct a void return...");
73 call->reply = dbus_message_new_method_return(call->message);
74 if (call->reply == NULL)
76 a2j_error("Failed to construct method return!");
77 return;
81 if (!dbus_connection_send(call->connection, call->reply, NULL))
83 a2j_error("Ran out of memory trying to queue method return");
86 dbus_connection_flush(call->connection);
87 dbus_message_unref(call->reply);
88 call->reply = NULL;
92 * Construct a method return which holds a single argument or, if
93 * the type parameter is DBUS_TYPE_INVALID, no arguments at all
94 * (a void message).
96 * The operation can only fail due to lack of memory, in which case
97 * there's no sense in trying to construct an error return. Instead,
98 * call->reply will be set to NULL and handled in send_method_return().
100 void
101 a2j_dbus_construct_method_return_single(
102 struct a2j_dbus_method_call * call_ptr,
103 int type,
104 void * arg)
106 DBusMessageIter iter;
108 call_ptr->reply = dbus_message_new_method_return(call_ptr->message);
109 if (call_ptr->reply == NULL)
111 goto fail_no_mem;
114 dbus_message_iter_init_append(call_ptr->reply, &iter);
116 if (!dbus_message_iter_append_basic(&iter, type, arg))
118 dbus_message_unref(call_ptr->reply);
119 call_ptr->reply = NULL;
120 goto fail_no_mem;
123 return;
125 fail_no_mem:
126 a2j_error("Ran out of memory trying to construct method return");
129 #define descriptor_ptr ((struct a2j_dbus_object_descriptor *)data)
131 DBusHandlerResult
132 a2j_dbus_message_handler(
133 DBusConnection * connection,
134 DBusMessage * message,
135 void * data)
137 struct a2j_dbus_method_call call;
138 const char *interface_name;
139 struct a2j_dbus_interface_descriptor ** interface_ptr_ptr;
141 /* Check if the message is a method call. If not, ignore it. */
142 if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_CALL)
144 goto handled;
147 /* Get the invoked method's name and make sure it's non-NULL. */
148 if (!(call.method_name = dbus_message_get_member (message)))
150 a2j_dbus_error(
151 &call,
152 A2J_DBUS_ERROR_UNKNOWN_METHOD,
153 "Received method call with empty method name");
154 goto send_return;
157 /* Initialize our data. */
158 call.context = descriptor_ptr->context;
159 call.connection = connection;
160 call.message = message;
161 call.reply = NULL;
163 /* Check if there's an interface specified for this method call. */
164 interface_name = dbus_message_get_interface (message);
165 if (interface_name != NULL)
167 /* Check if we can match the interface and method.
168 * The inteface handler functions only return false if the
169 * method name was unknown, otherwise they run the specified
170 * method and return TRUE.
173 interface_ptr_ptr = descriptor_ptr->interfaces;
175 while (*interface_ptr_ptr != NULL)
177 if (strcmp(interface_name, (*interface_ptr_ptr)->name) == 0)
179 if (!(*interface_ptr_ptr)->handler(&call, (*interface_ptr_ptr)->methods))
181 break;
184 goto send_return;
187 interface_ptr_ptr++;
190 else
192 /* No interface was specified so we have to try them all. This is
193 * dictated by the D-Bus specification which states that method calls
194 * omitting the interface must never be rejected.
197 interface_ptr_ptr = descriptor_ptr->interfaces;
199 while (*interface_ptr_ptr != NULL)
201 if ((*interface_ptr_ptr)->handler(&call, (*interface_ptr_ptr)->methods))
203 goto send_return;
206 interface_ptr_ptr++;
210 a2j_dbus_error(
211 &call,
212 A2J_DBUS_ERROR_UNKNOWN_METHOD,
213 "Method \"%s\" with signature \"%s\" on interface \"%s\" doesn't exist",
214 call.method_name,
215 dbus_message_get_signature(message),
216 interface_name);
218 send_return:
219 a2j_dbus_send_method_return(&call);
221 handled:
222 return DBUS_HANDLER_RESULT_HANDLED;
225 void
226 a2j_dbus_message_handler_unregister(
227 DBusConnection *connection,
228 void *data)
230 a2j_debug("Message handler was unregistered");
233 #undef descriptor_ptr
236 * Check if the supplied method name exists in method descriptor,
237 * if it does execute it and return TRUE. Otherwise return FALSE.
239 bool
240 a2j_dbus_run_method(
241 struct a2j_dbus_method_call *call,
242 const struct a2j_dbus_interface_method_descriptor * methods)
244 const struct a2j_dbus_interface_method_descriptor * method_ptr;
246 method_ptr = methods;
248 while (method_ptr->name != NULL)
250 if (strcmp(call->method_name, method_ptr->name) == 0)
252 method_ptr->handler(call);
253 return TRUE;
256 method_ptr++;
259 return FALSE;
262 static DBusConnection * g_dbus_connection_ptr;
263 static struct a2j_dbus_object_descriptor g_a2j_dbus_object_descriptor;
264 struct a2j_dbus_interface_descriptor * g_a2j_dbus_interfaces[] =
266 &g_a2j_iface_introspectable,
267 &g_a2j_iface_control,
268 NULL
271 bool
272 a2j_dbus_is_available()
274 return g_dbus_connection_ptr != NULL;
277 bool
278 a2j_dbus_init()
280 DBusError dbus_error;
281 int ret;
282 DBusObjectPathVTable vtable =
284 a2j_dbus_message_handler_unregister,
285 a2j_dbus_message_handler,
286 NULL
289 dbus_error_init(&dbus_error);
290 g_dbus_connection_ptr = dbus_bus_get(DBUS_BUS_SESSION, &dbus_error);
291 if (dbus_error_is_set(&dbus_error))
293 a2j_error("Failed to get bus: %s", dbus_error.message);
294 goto fail;
297 dbus_connection_set_exit_on_disconnect(g_dbus_connection_ptr, FALSE);
299 a2j_debug("D-Bus unique name is '%s'", dbus_bus_get_unique_name(g_dbus_connection_ptr));
301 ret = dbus_bus_request_name(g_dbus_connection_ptr, A2J_DBUS_SERVICE_NAME, DBUS_NAME_FLAG_DO_NOT_QUEUE, &dbus_error);
302 if (ret == -1)
304 a2j_error("Failed to acquire bus name: %s", dbus_error.message);
305 goto fail_unref_dbus_connection;
308 if (ret == DBUS_REQUEST_NAME_REPLY_EXISTS)
310 a2j_error("Requested bus name already exists");
311 goto fail_unref_dbus_connection;
314 g_a2j_dbus_object_descriptor.context = NULL;
315 g_a2j_dbus_object_descriptor.interfaces = g_a2j_dbus_interfaces;
317 if (!dbus_connection_register_object_path(
318 g_dbus_connection_ptr,
319 A2J_DBUS_OBJECT_PATH,
320 &vtable,
321 &g_a2j_dbus_object_descriptor))
323 a2j_error("Ran out of memory trying to register D-Bus object path");
324 goto fail_unref_dbus_connection;
327 return true;
329 fail_unref_dbus_connection:
330 dbus_connection_unref(g_dbus_connection_ptr);
331 g_dbus_connection_ptr = NULL;
333 fail:
335 return false;
338 bool
339 a2j_dbus_run(
340 int timeout_milliseconds)
342 return dbus_connection_read_write_dispatch(g_dbus_connection_ptr, timeout_milliseconds);
345 void
346 a2j_dbus_uninit()
348 dbus_connection_unref(g_dbus_connection_ptr);
349 g_dbus_connection_ptr = NULL;
352 void
353 a2j_dbus_signal(
354 const char * path,
355 const char * interface,
356 const char * name,
357 int type,
358 ...)
360 va_list ap;
361 DBusMessage * message_ptr;
363 a2j_debug("Sending signal %s.%s from %s", interface, name, path);
365 if (!a2j_dbus_is_available())
367 a2j_error("Internal error: cannot send D-Bus signal without D-Bus being initialized");
368 return;
371 message_ptr = dbus_message_new_signal (path, interface, name);
373 if (message_ptr == NULL)
375 a2j_error("Ran out of memory trying to create new signal");
376 return;
379 va_start(ap, type);
380 if (dbus_message_append_args_valist(message_ptr, type, ap))
382 if (!dbus_connection_send(g_dbus_connection_ptr, message_ptr, NULL))
384 a2j_error("Ran out of memory trying to queue signal");
387 dbus_connection_flush(g_dbus_connection_ptr);
389 else
391 a2j_error("Ran out of memory trying to append signal argument(s)");
393 va_end(ap);
395 dbus_message_unref(message_ptr);