website/index.html: Extend Feedback section (codeberg.org)
[a2jmidid.git] / dbus.c
blob6e403d7daf58266180002a93e4b57be9bd65cc08
1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
2 /*
3 * ALSA SEQ < - > JACK MIDI bridge
5 * Copyright (c) 2007,2008,2009 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 void a2j_dbus_construct_method_return_void(struct a2j_dbus_method_call * call_ptr)
131 call_ptr->reply = dbus_message_new_method_return(call_ptr->message);
132 if (call_ptr->reply == NULL)
134 a2j_error("Ran out of memory trying to construct method return");
138 #define descriptor_ptr ((struct a2j_dbus_object_descriptor *)data)
140 DBusHandlerResult
141 a2j_dbus_message_handler(
142 DBusConnection * connection,
143 DBusMessage * message,
144 void * data)
146 struct a2j_dbus_method_call call;
147 const char *interface_name;
148 struct a2j_dbus_interface_descriptor ** interface_ptr_ptr;
150 /* Check if the message is a method call. If not, ignore it. */
151 if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_CALL)
153 goto handled;
156 /* Get the invoked method's name and make sure it's non-NULL. */
157 if (!(call.method_name = dbus_message_get_member (message)))
159 a2j_dbus_error(
160 &call,
161 A2J_DBUS_ERROR_UNKNOWN_METHOD,
162 "Received method call with empty method name");
163 goto send_return;
166 /* Initialize our data. */
167 call.context = descriptor_ptr->context;
168 call.connection = connection;
169 call.message = message;
170 call.reply = NULL;
172 /* Check if there's an interface specified for this method call. */
173 interface_name = dbus_message_get_interface (message);
174 if (interface_name != NULL)
176 /* Check if we can match the interface and method.
177 * The inteface handler functions only return false if the
178 * method name was unknown, otherwise they run the specified
179 * method and return TRUE.
182 interface_ptr_ptr = descriptor_ptr->interfaces;
184 while (*interface_ptr_ptr != NULL)
186 if (strcmp(interface_name, (*interface_ptr_ptr)->name) == 0)
188 if (!(*interface_ptr_ptr)->handler(&call, (*interface_ptr_ptr)->methods))
190 break;
193 goto send_return;
196 interface_ptr_ptr++;
199 else
201 /* No interface was specified so we have to try them all. This is
202 * dictated by the D-Bus specification which states that method calls
203 * omitting the interface must never be rejected.
206 interface_ptr_ptr = descriptor_ptr->interfaces;
208 while (*interface_ptr_ptr != NULL)
210 if ((*interface_ptr_ptr)->handler(&call, (*interface_ptr_ptr)->methods))
212 goto send_return;
215 interface_ptr_ptr++;
219 a2j_dbus_error(
220 &call,
221 A2J_DBUS_ERROR_UNKNOWN_METHOD,
222 "Method \"%s\" with signature \"%s\" on interface \"%s\" doesn't exist",
223 call.method_name,
224 dbus_message_get_signature(message),
225 interface_name);
227 send_return:
228 a2j_dbus_send_method_return(&call);
230 handled:
231 return DBUS_HANDLER_RESULT_HANDLED;
234 void
235 a2j_dbus_message_handler_unregister(
236 DBusConnection *connection,
237 void *data)
239 ((void)(connection)); /* unreferenced parameter */
240 ((void)(data)); /* unreferenced parameter */
241 a2j_debug("Message handler was unregistered");
244 #undef descriptor_ptr
247 * Check if the supplied method name exists in method descriptor,
248 * if it does execute it and return TRUE. Otherwise return FALSE.
250 bool
251 a2j_dbus_run_method(
252 struct a2j_dbus_method_call *call,
253 const struct a2j_dbus_interface_method_descriptor * methods)
255 const struct a2j_dbus_interface_method_descriptor * method_ptr;
257 method_ptr = methods;
259 while (method_ptr->name != NULL)
261 if (strcmp(call->method_name, method_ptr->name) == 0)
263 method_ptr->handler(call);
264 return TRUE;
267 method_ptr++;
270 return FALSE;
273 static DBusConnection * g_dbus_connection_ptr;
274 static struct a2j_dbus_object_descriptor g_a2j_dbus_object_descriptor;
275 struct a2j_dbus_interface_descriptor * g_a2j_dbus_interfaces[] =
277 &g_a2j_iface_introspectable,
278 &g_a2j_iface_control,
279 NULL
282 bool
283 a2j_dbus_is_available(void)
285 return g_dbus_connection_ptr != NULL;
288 bool
289 a2j_dbus_init(void)
291 DBusError dbus_error;
292 int ret;
293 DBusObjectPathVTable vtable = {
294 .unregister_function = a2j_dbus_message_handler_unregister,
295 .message_function = a2j_dbus_message_handler
298 dbus_error_init(&dbus_error);
299 g_dbus_connection_ptr = dbus_bus_get(DBUS_BUS_SESSION, &dbus_error);
300 if (dbus_error_is_set(&dbus_error))
302 a2j_error("Failed to get bus: %s", dbus_error.message);
303 goto fail;
306 dbus_connection_set_exit_on_disconnect(g_dbus_connection_ptr, FALSE);
308 a2j_debug("D-Bus unique name is '%s'", dbus_bus_get_unique_name(g_dbus_connection_ptr));
310 ret = dbus_bus_request_name(g_dbus_connection_ptr, A2J_DBUS_SERVICE_NAME, DBUS_NAME_FLAG_DO_NOT_QUEUE, &dbus_error);
311 if (ret == -1)
313 a2j_error("Failed to acquire bus name: %s", dbus_error.message);
314 goto fail_unref_dbus_connection;
317 if (ret == DBUS_REQUEST_NAME_REPLY_EXISTS)
319 a2j_error("Requested bus name already exists");
320 goto fail_unref_dbus_connection;
323 g_a2j_dbus_object_descriptor.context = NULL;
324 g_a2j_dbus_object_descriptor.interfaces = g_a2j_dbus_interfaces;
326 if (!dbus_connection_register_object_path(
327 g_dbus_connection_ptr,
328 A2J_DBUS_OBJECT_PATH,
329 &vtable,
330 &g_a2j_dbus_object_descriptor))
332 a2j_error("Ran out of memory trying to register D-Bus object path");
333 goto fail_unref_dbus_connection;
336 return true;
338 fail_unref_dbus_connection:
339 dbus_connection_unref(g_dbus_connection_ptr);
340 g_dbus_connection_ptr = NULL;
342 fail:
344 return false;
347 bool
348 a2j_dbus_run(
349 int timeout_milliseconds)
351 return dbus_connection_read_write_dispatch(g_dbus_connection_ptr, timeout_milliseconds);
354 void
355 a2j_dbus_uninit(void)
357 dbus_connection_unref(g_dbus_connection_ptr);
358 g_dbus_connection_ptr = NULL;
361 void
362 a2j_dbus_signal(
363 const char * path,
364 const char * interface,
365 const char * name,
366 int type,
367 ...)
369 va_list ap;
370 DBusMessage * message_ptr;
372 a2j_debug("Sending signal %s.%s from %s", interface, name, path);
374 if (!a2j_dbus_is_available())
376 a2j_error("Internal error: cannot send D-Bus signal without D-Bus being initialized");
377 return;
380 message_ptr = dbus_message_new_signal (path, interface, name);
382 if (message_ptr == NULL)
384 a2j_error("Ran out of memory trying to create new signal");
385 return;
388 va_start(ap, type);
389 if (dbus_message_append_args_valist(message_ptr, type, ap))
391 if (!dbus_connection_send(g_dbus_connection_ptr, message_ptr, NULL))
393 a2j_error("Ran out of memory trying to queue signal");
396 dbus_connection_flush(g_dbus_connection_ptr);
398 else
400 a2j_error("Ran out of memory trying to append signal argument(s)");
402 va_end(ap);
404 dbus_message_unref(message_ptr);