1 /* -*- Mode: C ; c-basic-offset: 4 -*- */
3 Copyright (C) 2007,2008,2010 Nedko Arnaudov
4 Copyright (C) 2007-2008 Juuso Alasuutari
5 Copyright (C) 2008 Marc-Olivier Barre
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #if defined(HAVE_CONFIG_H)
33 #include <dbus/dbus.h>
41 #include "controller.h"
42 #include "jack/jack.h"
43 #include "jack/jslist.h"
44 #include "jack/control.h"
46 #include "../siginfo/siginfo.h"
49 static char * g_log_filename
;
50 static ino_t g_log_file_ino
;
52 char *g_jackdbus_config_dir
;
53 size_t g_jackdbus_config_dir_len
; /* without terminating '\0' char */
54 char *g_jackdbus_log_dir
;
55 size_t g_jackdbus_log_dir_len
; /* without terminating '\0' char */
57 DBusConnection
*g_connection
;
60 jack_dbus_send_signal(
61 const char *sender_object_path
,
63 const char *signal_name
,
67 DBusMessage
*message_ptr
;
70 va_start(ap
, first_arg_type
);
72 message_ptr
= dbus_message_new_signal(sender_object_path
, iface
, signal_name
);
73 if (message_ptr
== NULL
)
75 jack_error("dbus_message_new_signal() failed.");
79 if (!dbus_message_append_args_valist(message_ptr
, first_arg_type
, ap
))
81 jack_error("dbus_message_append_args_valist() failed.");
85 /* Add message to outgoing message queue */
86 if (!dbus_connection_send(g_connection
, message_ptr
, NULL
))
88 jack_error("dbus_connection_send() failed.");
93 dbus_message_unref(message_ptr
);
100 * Send a method return.
102 * If call->reply is NULL (i.e. a message construct method failed
103 * due to lack of memory) attempt to send a void method return.
107 jack_dbus_send_method_return(
108 struct jack_dbus_method_call
* call
)
110 if (call
->message
== NULL
)
119 if (!dbus_connection_send (call
->connection
, call
->reply
, NULL
))
121 jack_error ("Ran out of memory trying to queue method return");
124 dbus_connection_flush (call
->connection
);
125 dbus_message_unref (call
->reply
);
130 jack_error ("send_method_return() called with a NULL message,"
131 " trying to construct a void return...");
133 if ((call
->reply
= dbus_message_new_method_return (call
->message
)))
139 jack_error ("Failed to construct method return!");
144 #define object_ptr ((struct jack_dbus_object_descriptor *)data)
147 * The D-Bus message handler for object path /org/jackaudio/Controller.
150 jack_dbus_message_handler(
151 DBusConnection
*connection
,
152 DBusMessage
*message
,
155 struct jack_dbus_method_call call
;
156 const char *interface_name
;
157 struct jack_dbus_interface_descriptor
** interface_ptr_ptr
;
159 /* Check if the message is a method call. If not, ignore it. */
160 if (dbus_message_get_type (message
) != DBUS_MESSAGE_TYPE_METHOD_CALL
)
165 /* Get the invoked method's name and make sure it's non-NULL. */
166 if (!(call
.method_name
= dbus_message_get_member (message
)))
170 JACK_DBUS_ERROR_UNKNOWN_METHOD
,
171 "Received method call with empty method name");
175 /* Initialize our data. */
176 call
.context
= object_ptr
->context
;
177 call
.connection
= connection
;
178 call
.message
= message
;
181 /* Check if there's an interface specified for this method call. */
182 interface_name
= dbus_message_get_interface (message
);
183 if (interface_name
!= NULL
)
185 /* Check if we can match the interface and method.
186 * The interface handler functions only return false if the
187 * method name was unknown, otherwise they run the specified
188 * method and return TRUE.
191 interface_ptr_ptr
= object_ptr
->interfaces
;
193 while (*interface_ptr_ptr
!= NULL
)
195 if (strcmp(interface_name
, (*interface_ptr_ptr
)->name
) == 0)
197 if (!(*interface_ptr_ptr
)->handler(&call
, (*interface_ptr_ptr
)->methods
))
210 /* No interface was specified so we have to try them all. This is
211 * dictated by the D-Bus specification which states that method calls
212 * omitting the interface must never be rejected.
215 interface_ptr_ptr
= object_ptr
->interfaces
;
217 while (*interface_ptr_ptr
!= NULL
)
219 if ((*interface_ptr_ptr
)->handler(&call
, (*interface_ptr_ptr
)->methods
))
230 JACK_DBUS_ERROR_UNKNOWN_METHOD
,
231 "Method \"%s\" with signature \"%s\" on interface \"%s\" doesn't exist",
233 dbus_message_get_signature(message
),
237 jack_dbus_send_method_return(&call
);
240 return DBUS_HANDLER_RESULT_HANDLED
;
244 jack_dbus_message_handler_unregister(
245 DBusConnection
*connection
,
248 jack_info ("Message handler was unregistered");
254 * Check if the supplied method name exists in org.jackaudio.JackConfigure,
255 * if it does execute it and return TRUE. Otherwise return FALSE.
258 jack_dbus_run_method(
259 struct jack_dbus_method_call
*call
,
260 const struct jack_dbus_interface_method_descriptor
* methods
)
262 const struct jack_dbus_interface_method_descriptor
* method_ptr
;
264 method_ptr
= methods
;
266 while (method_ptr
->name
!= NULL
)
268 if (strcmp(call
->method_name
, method_ptr
->name
) == 0)
270 method_ptr
->handler(call
);
281 * Read arguments from a method call.
282 * If the operation fails construct an error and return false,
283 * otherwise return true.
286 jack_dbus_get_method_args(
287 struct jack_dbus_method_call
*call
,
295 va_start (args
, type
);
296 dbus_error_init (&error
);
298 if (!dbus_message_get_args_valist (call
->message
, &error
, type
, args
))
300 jack_dbus_error (call
, JACK_DBUS_ERROR_INVALID_ARGS
,
301 "Invalid arguments to method \"%s\"",
306 dbus_error_free (&error
);
313 * Read a string and a variant argument from a method call.
314 * If the operation fails construct an error and return false,
315 * otherwise return true.
318 jack_dbus_get_method_args_string_and_variant(
319 struct jack_dbus_method_call
*call
,
324 DBusMessageIter iter
, sub_iter
;
326 /* First we want a string... */
327 if (dbus_message_iter_init (call
->message
, &iter
)
328 && dbus_message_iter_get_arg_type (&iter
) == DBUS_TYPE_STRING
)
330 dbus_message_iter_get_basic (&iter
, arg1
);
331 dbus_message_iter_next (&iter
);
333 /* ...and then a variant. */
334 if (dbus_message_iter_get_arg_type (&iter
) == DBUS_TYPE_VARIANT
)
336 dbus_message_iter_recurse (&iter
, &sub_iter
);
337 dbus_message_iter_get_basic (&sub_iter
, arg2
);
338 *type_ptr
= dbus_message_iter_get_arg_type (&sub_iter
);
340 /* Got what we wanted. */
345 jack_dbus_error (call
, JACK_DBUS_ERROR_INVALID_ARGS
,
346 "Invalid arguments to method \"%s\"",
353 * Read two strings and a variant argument from a method call.
354 * If the operation fails construct an error and return false,
355 * otherwise return true.
358 jack_dbus_get_method_args_two_strings_and_variant(
359 struct jack_dbus_method_call
*call
,
365 DBusMessageIter iter
, sub_iter
;
367 /* First we want a string... */
368 if (dbus_message_iter_init (call
->message
, &iter
)
369 && dbus_message_iter_get_arg_type (&iter
) == DBUS_TYPE_STRING
)
371 dbus_message_iter_get_basic (&iter
, arg1
);
372 dbus_message_iter_next (&iter
);
374 /* ...and then a second string. */
375 if (dbus_message_iter_get_arg_type (&iter
) != DBUS_TYPE_STRING
)
380 /* Got what we wanted. */
381 dbus_message_iter_get_basic (&iter
, arg2
);
382 dbus_message_iter_next (&iter
);
384 /* ...and then a variant. */
385 if (dbus_message_iter_get_arg_type (&iter
) == DBUS_TYPE_VARIANT
)
387 dbus_message_iter_recurse (&iter
, &sub_iter
);
388 dbus_message_iter_get_basic (&sub_iter
, arg3
);
389 *type_ptr
= dbus_message_iter_get_arg_type (&sub_iter
);
391 /* Got what we wanted. */
396 jack_dbus_error (call
, JACK_DBUS_ERROR_INVALID_ARGS
,
397 "Invalid arguments to method \"%s\"",
404 * Append a variant type to a D-Bus message.
405 * Return false if something fails, true otherwise.
408 jack_dbus_message_append_variant(
409 DBusMessageIter
*iter
,
411 const char *signature
,
414 DBusMessageIter sub_iter
;
416 /* Open a variant container. */
417 if (!dbus_message_iter_open_container (iter
, DBUS_TYPE_VARIANT
, signature
, &sub_iter
))
422 /* Append the supplied value. */
423 if (!dbus_message_iter_append_basic (&sub_iter
, type
, (const void *) arg
))
425 dbus_message_iter_close_container (iter
, &sub_iter
);
429 /* Close the container. */
430 if (!dbus_message_iter_close_container (iter
, &sub_iter
))
442 * Construct an empty method return message.
444 * The operation can only fail due to lack of memory, in which case
445 * there's no sense in trying to construct an error return. Instead,
446 * call->reply will be set to NULL and handled in send_method_return().
449 jack_dbus_construct_method_return_empty(
450 struct jack_dbus_method_call
* call
)
452 call
->reply
= dbus_message_new_method_return (call
->message
);
454 if (call
->reply
== NULL
)
456 jack_error ("Ran out of memory trying to construct method return");
461 * Construct a method return which holds a single argument or, if
462 * the type parameter is DBUS_TYPE_INVALID, no arguments at all
465 * The operation can only fail due to lack of memory, in which case
466 * there's no sense in trying to construct an error return. Instead,
467 * call->reply will be set to NULL and handled in send_method_return().
470 jack_dbus_construct_method_return_single(
471 struct jack_dbus_method_call
*call
,
475 DBusMessageIter iter
;
476 call
->reply
= dbus_message_new_method_return (call
->message
);
478 if (call
->reply
== NULL
)
483 /* Void method return requested by caller. */
484 if (type
== DBUS_TYPE_INVALID
)
489 /* Prevent crash on NULL input string. */
490 else if (type
== DBUS_TYPE_STRING
&& arg
.string
== NULL
)
495 dbus_message_iter_init_append (call
->reply
, &iter
);
497 if (!dbus_message_iter_append_basic (&iter
, type
, (const void *) &arg
))
499 dbus_message_unref (call
->reply
);
507 jack_error ("Ran out of memory trying to construct method return");
511 * Construct a method return which holds an array of strings.
513 * The operation can only fail due to lack of memory, in which case
514 * there's no sense in trying to construct an error return. Instead,
515 * call->reply will be set to NULL and handled in send_method_return().
518 jack_dbus_construct_method_return_array_of_strings(
519 struct jack_dbus_method_call
*call
,
520 unsigned int num_members
,
523 DBusMessageIter iter
, sub_iter
;
526 call
->reply
= dbus_message_new_method_return (call
->message
);
532 dbus_message_iter_init_append (call
->reply
, &iter
);
534 if (!dbus_message_iter_open_container (&iter
, DBUS_TYPE_ARRAY
, "s", &sub_iter
))
539 for (i
= 0; i
< num_members
; ++i
)
541 if (!dbus_message_iter_append_basic (&sub_iter
, DBUS_TYPE_STRING
, (const void *) &array
[i
]))
543 dbus_message_iter_close_container (&iter
, &sub_iter
);
548 if (!dbus_message_iter_close_container (&iter
, &sub_iter
))
556 dbus_message_unref (call
->reply
);
560 jack_error ("Ran out of memory trying to construct method return");
563 static bool jack_dbus_log_open(void)
569 if (g_logfile
!= NULL
)
571 ret
= stat(g_log_filename
, &st
);
572 if (ret
!= 0 || g_log_file_ino
!= st
.st_ino
)
582 for (retry
= 0; retry
< 10; retry
++)
584 g_logfile
= fopen(g_log_filename
, "a");
585 if (g_logfile
== NULL
)
587 fprintf(stderr
, "Cannot open jackdbus log file \"%s\": %d (%s)\n", g_log_filename
, errno
, strerror(errno
));
591 ret
= stat(g_log_filename
, &st
);
594 g_log_file_ino
= st
.st_ino
;
602 fprintf(stderr
, "Cannot stat just opened jackdbus log file \"%s\": %d (%s). %d retries\n", g_log_filename
, errno
, strerror(errno
), retry
);
607 jack_dbus_info_callback(const char *msg
)
610 char timestamp_str
[26];
613 ctime_r(×tamp
, timestamp_str
);
614 timestamp_str
[24] = 0;
616 if (jack_dbus_log_open())
618 fprintf(g_logfile
, "%s: %s\n", timestamp_str
, msg
);
623 #define ANSI_BOLD_ON "\033[1m"
624 #define ANSI_BOLD_OFF "\033[22m"
625 #define ANSI_COLOR_RED "\033[31m"
626 #define ANSI_RESET "\033[0m"
629 jack_dbus_error_callback(const char *msg
)
632 char timestamp_str
[26];
635 ctime_r(×tamp
, timestamp_str
);
636 timestamp_str
[24] = 0;
638 if (jack_dbus_log_open())
640 fprintf(g_logfile
, "%s: " ANSI_BOLD_ON ANSI_COLOR_RED
"ERROR: %s" ANSI_RESET
"\n", timestamp_str
, msg
);
646 ensure_dir_exist(const char *dirname
, int mode
)
649 if (stat(dirname
, &st
) != 0)
653 printf("Directory \"%s\" does not exist. Creating...\n", dirname
);
654 if (mkdir(dirname
, mode
) != 0)
656 fprintf(stderr
, "Failed to create \"%s\" directory: %d (%s)\n", dirname
, errno
, strerror(errno
));
662 fprintf(stderr
, "Failed to stat \"%s\": %d (%s)\n", dirname
, errno
, strerror(errno
));
668 if (!S_ISDIR(st
.st_mode
))
670 fprintf(stderr
, "\"%s\" exists but is not directory.\n", dirname
);
678 pathname_cat(const char *pathname_a
, const char *pathname_b
)
681 int pathname_a_len
, pathname_b_len
, pathname_len
;
682 pathname_a_len
= strlen(pathname_a
);
683 pathname_b_len
= strlen(pathname_b
);
684 pathname
= malloc(pathname_a_len
+ pathname_b_len
+ 1);
685 if (pathname
== NULL
)
687 fprintf(stderr
, "Out of memory\n");
690 memcpy(pathname
, pathname_a
, pathname_a_len
);
691 memcpy(pathname
+ pathname_a_len
, pathname_b
, pathname_b_len
);
692 pathname_len
= pathname_a_len
+ pathname_b_len
;
693 pathname
[pathname_len
] = 0;
700 const char *home_dir
, *xdg_config_home
, *xdg_log_home
;
702 home_dir
= getenv("HOME");
703 if (home_dir
== NULL
)
705 fprintf(stderr
, "Environment variable HOME not set\n");
709 xdg_config_home
= getenv("XDG_CONFIG_HOME");
710 if (xdg_config_home
== NULL
)
712 if (!(xdg_config_home
= pathname_cat(home_dir
, DEFAULT_XDG_CONFIG
))) goto fail
;
715 if (!(xdg_log_home
= pathname_cat(home_dir
, DEFAULT_XDG_LOG
))) goto fail
;
717 if (!(g_jackdbus_config_dir
= pathname_cat(xdg_config_home
, JACKDBUS_DIR
))) goto fail
;
718 if (!(g_jackdbus_log_dir
= pathname_cat(xdg_log_home
, JACKDBUS_DIR
))) goto fail
;
720 if (!ensure_dir_exist(xdg_config_home
, 0700))
725 if (!ensure_dir_exist(xdg_log_home
, 0700))
730 if (!ensure_dir_exist(g_jackdbus_config_dir
, 0700))
732 free(g_jackdbus_config_dir
);
735 g_jackdbus_config_dir_len
= strlen(g_jackdbus_config_dir
);
737 if (!ensure_dir_exist(g_jackdbus_log_dir
, 0700))
739 free(g_jackdbus_log_dir
);
742 g_jackdbus_log_dir_len
= strlen(g_jackdbus_log_dir
);
753 free(g_jackdbus_config_dir
);
754 free(g_jackdbus_log_dir
);
757 static bool log_init(void)
761 log_len
= strlen(JACKDBUS_LOG
);
763 g_log_filename
= malloc(g_jackdbus_log_dir_len
+ log_len
+ 1);
764 if (g_log_filename
== NULL
)
766 fprintf(stderr
, "Out of memory\n");
770 memcpy(g_log_filename
, g_jackdbus_log_dir
, g_jackdbus_log_dir_len
);
771 memcpy(g_log_filename
+ g_jackdbus_log_dir_len
, JACKDBUS_LOG
, log_len
);
772 g_log_filename
[g_jackdbus_log_dir_len
+ log_len
] = 0;
774 if (!jack_dbus_log_open())
782 static void log_uninit(void)
784 if (g_logfile
!= NULL
)
789 free(g_log_filename
);
794 void *dbus_call_context_ptr
,
795 const char *error_name
,
802 va_start(ap
, format
);
804 vsnprintf(buffer
, sizeof(buffer
), format
, ap
);
806 jack_error_callback(buffer
);
807 if (dbus_call_context_ptr
!= NULL
)
809 if (((struct jack_dbus_method_call
*)dbus_call_context_ptr
)->reply
!= NULL
)
811 dbus_message_unref(((struct jack_dbus_method_call
*)dbus_call_context_ptr
)->reply
);
812 ((struct jack_dbus_method_call
*)dbus_call_context_ptr
)->reply
= NULL
;
815 ((struct jack_dbus_method_call
*)dbus_call_context_ptr
)->reply
= dbus_message_new_error(
816 ((struct jack_dbus_method_call
*)dbus_call_context_ptr
)->message
,
825 jack_dbus_only_error(
826 void *dbus_call_context_ptr
,
827 const char *error_name
,
834 va_start(ap
, format
);
836 vsnprintf(buffer
, sizeof(buffer
), format
, ap
);
838 if (((struct jack_dbus_method_call
*)dbus_call_context_ptr
)->reply
!= NULL
)
840 dbus_message_unref(((struct jack_dbus_method_call
*)dbus_call_context_ptr
)->reply
);
841 ((struct jack_dbus_method_call
*)dbus_call_context_ptr
)->reply
= NULL
;
844 ((struct jack_dbus_method_call
*)dbus_call_context_ptr
)->reply
= dbus_message_new_error(
845 ((struct jack_dbus_method_call
*)dbus_call_context_ptr
)->message
,
853 main (int argc
, char **argv
)
857 void *controller_ptr
;
859 char timestamp_str
[26];
863 ctime_r(&st
.st_mtime
, timestamp_str
);
864 timestamp_str
[24] = 0;
866 if (!jack_controller_settings_init())
872 if (argc
!= 2 || strcmp(argv
[1], "auto") != 0)
877 "jackdbus should be auto-executed by D-Bus message bus daemon.\n"
878 "If you want to run it manually anyway, specify \"auto\" as only parameter\n");
879 goto fail_uninit_xml
;
885 goto fail_uninit_xml
;
891 goto fail_uninit_paths
;
894 #if !defined(DISABLE_SIGNAL_MAGIC)
895 jackctl_setup_signals(0);
898 jack_set_error_function(jack_dbus_error_callback
);
899 jack_set_info_function(jack_dbus_info_callback
);
902 /* setup our SIGSEGV magic that prints nice stack in our logfile */
906 jack_info("------------------");
907 jack_info("jackdbus version %s built from %s on %s", JACK_VERSION
, GIT_VERSION
, timestamp_str
);
908 jack_info("JACK server version %s", jack_get_version_string());
909 jack_info("jackdbus controller activated.");
911 if (!dbus_threads_init_default())
913 jack_error("dbus_threads_init_default() failed");
915 goto fail_uninit_log
;
918 dbus_error_init (&error
);
919 g_connection
= dbus_bus_get (DBUS_BUS_SESSION
, &error
);
920 if (dbus_error_is_set (&error
))
922 jack_error("Cannot connect to D-Bus session bus: %s", error
.message
);
924 goto fail_uninit_log
;
927 ret
= dbus_bus_request_name(
929 "org.jackaudio.service",
930 DBUS_NAME_FLAG_DO_NOT_QUEUE
,
934 jack_error("Cannot request service name: %s", error
.message
);
935 dbus_error_free(&error
);
937 goto fail_unref_connection
;
939 else if (ret
== DBUS_REQUEST_NAME_REPLY_EXISTS
)
941 jack_error("Requested D-Bus service name already exists");
943 goto fail_unref_connection
;
946 controller_ptr
= jack_controller_create(g_connection
);
948 if (controller_ptr
== NULL
)
951 goto fail_unref_connection
;
954 jack_info("Listening for D-Bus messages");
956 g_exit_command
= FALSE
;
957 while (!g_exit_command
&& dbus_connection_read_write_dispatch (g_connection
, 200))
959 jack_controller_run(controller_ptr
);
962 jack_controller_destroy(controller_ptr
);
964 jack_info("Controller deactivated.");
968 fail_unref_connection
:
969 dbus_connection_unref(g_connection
);
978 jack_controller_settings_uninit();