Correct netjack2 socket init code.
[jack2.git] / dbus / jackdbus.c
blobeb86308bd5657f8216eebcafd72d7a341a3f47ff
1 /* -*- Mode: C ; c-basic-offset: 4 -*- */
2 /*
3 Copyright (C) 2007,2008 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)
23 #include "config.h"
24 #endif
26 #include <stdbool.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <errno.h>
31 #include <sys/stat.h>
32 #include <signal.h>
33 #include <dbus/dbus.h>
34 #include <pthread.h>
35 #include <unistd.h>
37 #include "config.h"
39 #include "jackdbus.h"
40 #include "controller.h"
41 #include "jack/jack.h"
42 #include "jack/jslist.h"
43 #include "jack/control.h"
44 #include "sigsegv.h"
45 #include "svnversion.h"
47 FILE *g_logfile;
48 char *g_jackdbus_config_dir;
49 size_t g_jackdbus_config_dir_len; /* without terminating '\0' char */
50 char *g_jackdbus_log_dir;
51 size_t g_jackdbus_log_dir_len; /* without terminating '\0' char */
52 int g_exit_command;
53 DBusConnection *g_connection;
55 void
56 jack_dbus_send_signal(
57 const char *sender_object_path,
58 const char *iface,
59 const char *signal_name,
60 int first_arg_type,
61 ...)
63 DBusMessage *message_ptr;
64 va_list ap;
66 va_start(ap, first_arg_type);
68 message_ptr = dbus_message_new_signal(sender_object_path, iface, signal_name);
69 if (message_ptr == NULL)
71 jack_error("dbus_message_new_signal() failed.");
72 goto exit;
75 if (!dbus_message_append_args_valist(message_ptr, first_arg_type, ap))
77 jack_error("dbus_message_append_args_valist() failed.");
78 goto unref;
81 /* Add message to outgoing message queue */
82 if (!dbus_connection_send(g_connection, message_ptr, NULL))
84 jack_error("dbus_connection_send() failed.");
85 goto unref;
88 unref:
89 dbus_message_unref(message_ptr);
91 exit:
92 va_end(ap);
96 * Send a method return.
98 * If call->reply is NULL (i.e. a message construct method failed
99 * due to lack of memory) attempt to send a void method return.
101 static
102 void
103 jack_dbus_send_method_return(
104 struct jack_dbus_method_call * call)
106 if (call->reply)
108 retry_send:
109 if (!dbus_connection_send (call->connection, call->reply, NULL))
111 jack_error ("Ran out of memory trying to queue method return");
114 dbus_connection_flush (call->connection);
115 dbus_message_unref (call->reply);
116 call->reply = NULL;
118 else
120 jack_error ("send_method_return() called with a NULL message,"
121 " trying to construct a void return...");
123 if ((call->reply = dbus_message_new_method_return (call->message)))
125 goto retry_send;
127 else
129 jack_error ("Failed to construct method return!");
134 #define object_ptr ((struct jack_dbus_object_descriptor *)data)
137 * The D-Bus message handler for object path /org/jackaudio/Controller.
139 DBusHandlerResult
140 jack_dbus_message_handler(
141 DBusConnection *connection,
142 DBusMessage *message,
143 void *data)
145 struct jack_dbus_method_call call;
146 const char *interface_name;
147 struct jack_dbus_interface_descriptor ** interface_ptr_ptr;
149 /* Check if the message is a method call. If not, ignore it. */
150 if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_CALL)
152 goto handled;
155 /* Get the invoked method's name and make sure it's non-NULL. */
156 if (!(call.method_name = dbus_message_get_member (message)))
158 jack_dbus_error(
159 &call,
160 JACK_DBUS_ERROR_UNKNOWN_METHOD,
161 "Received method call with empty method name");
162 goto send_return;
165 /* Initialize our data. */
166 call.context = object_ptr->context;
167 call.connection = connection;
168 call.message = message;
169 call.reply = NULL;
171 /* Check if there's an interface specified for this method call. */
172 interface_name = dbus_message_get_interface (message);
173 if (interface_name != NULL)
175 /* Check if we can match the interface and method.
176 * The inteface handler functions only return false if the
177 * method name was unknown, otherwise they run the specified
178 * method and return TRUE.
181 interface_ptr_ptr = object_ptr->interfaces;
183 while (*interface_ptr_ptr != NULL)
185 if (strcmp(interface_name, (*interface_ptr_ptr)->name) == 0)
187 if (!(*interface_ptr_ptr)->handler(&call, (*interface_ptr_ptr)->methods))
189 break;
192 goto send_return;
195 interface_ptr_ptr++;
198 else
200 /* No interface was specified so we have to try them all. This is
201 * dictated by the D-Bus specification which states that method calls
202 * omitting the interface must never be rejected.
205 interface_ptr_ptr = object_ptr->interfaces;
207 while (*interface_ptr_ptr != NULL)
209 if ((*interface_ptr_ptr)->handler(&call, (*interface_ptr_ptr)->methods))
211 goto send_return;
214 interface_ptr_ptr++;
218 jack_dbus_error(
219 &call,
220 JACK_DBUS_ERROR_UNKNOWN_METHOD,
221 "Method \"%s\" with signature \"%s\" on interface \"%s\" doesn't exist",
222 call.method_name,
223 dbus_message_get_signature(message),
224 interface_name);
226 send_return:
227 jack_dbus_send_method_return(&call);
229 handled:
230 return DBUS_HANDLER_RESULT_HANDLED;
233 void
234 jack_dbus_message_handler_unregister(
235 DBusConnection *connection,
236 void *data)
238 jack_info ("Message handler was unregistered");
241 #undef object_ptr
244 * Check if the supplied method name exists in org.jackaudio.JackConfigure,
245 * if it does execute it and return TRUE. Otherwise return FALSE.
247 bool
248 jack_dbus_run_method(
249 struct jack_dbus_method_call *call,
250 const struct jack_dbus_interface_method_descriptor * methods)
252 const struct jack_dbus_interface_method_descriptor * method_ptr;
254 method_ptr = methods;
256 while (method_ptr->name != NULL)
258 if (strcmp(call->method_name, method_ptr->name) == 0)
260 method_ptr->handler(call);
261 return TRUE;
264 method_ptr++;
267 return FALSE;
271 * Read arguments from a method call.
272 * If the operation fails construct an error and return false,
273 * otherwise return true.
275 bool
276 jack_dbus_get_method_args(
277 struct jack_dbus_method_call *call,
278 int type,
279 ...)
281 va_list args;
282 DBusError error;
283 bool retval = true;
285 va_start (args, type);
286 dbus_error_init (&error);
288 if (!dbus_message_get_args_valist (call->message, &error, type, args))
290 jack_dbus_error (call, JACK_DBUS_ERROR_INVALID_ARGS,
291 "Invalid arguments to method \"%s\"",
292 call->method_name);
293 retval = false;
296 dbus_error_free (&error);
297 va_end (args);
299 return retval;
303 * Read a string and a variant argument from a method call.
304 * If the operation fails construct an error and return false,
305 * otherwise return true.
307 bool
308 jack_dbus_get_method_args_string_and_variant(
309 struct jack_dbus_method_call *call,
310 const char **arg1,
311 message_arg_t *arg2,
312 int *type_ptr)
314 DBusMessageIter iter, sub_iter;
316 /* First we want a string... */
317 if (dbus_message_iter_init (call->message, &iter)
318 && dbus_message_iter_get_arg_type (&iter) == DBUS_TYPE_STRING)
320 dbus_message_iter_get_basic (&iter, arg1);
321 dbus_message_iter_next (&iter);
323 /* ...and then a variant. */
324 if (dbus_message_iter_get_arg_type (&iter) == DBUS_TYPE_VARIANT)
326 dbus_message_iter_recurse (&iter, &sub_iter);
327 dbus_message_iter_get_basic (&sub_iter, arg2);
328 *type_ptr = dbus_message_iter_get_arg_type (&sub_iter);
330 /* Got what we wanted. */
331 return true;
335 jack_dbus_error (call, JACK_DBUS_ERROR_INVALID_ARGS,
336 "Invalid arguments to method \"%s\"",
337 call->method_name);
339 return false;
343 * Read two strings and a variant argument from a method call.
344 * If the operation fails construct an error and return false,
345 * otherwise return true.
347 bool
348 jack_dbus_get_method_args_two_strings_and_variant(
349 struct jack_dbus_method_call *call,
350 const char **arg1,
351 const char **arg2,
352 message_arg_t *arg3,
353 int *type_ptr)
355 DBusMessageIter iter, sub_iter;
357 /* First we want a string... */
358 if (dbus_message_iter_init (call->message, &iter)
359 && dbus_message_iter_get_arg_type (&iter) == DBUS_TYPE_STRING)
361 dbus_message_iter_get_basic (&iter, arg1);
362 dbus_message_iter_next (&iter);
364 /* ...and then a second string. */
365 if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
367 return false;
370 /* Got what we wanted. */
371 dbus_message_iter_get_basic (&iter, arg2);
372 dbus_message_iter_next (&iter);
374 /* ...and then a variant. */
375 if (dbus_message_iter_get_arg_type (&iter) == DBUS_TYPE_VARIANT)
377 dbus_message_iter_recurse (&iter, &sub_iter);
378 dbus_message_iter_get_basic (&sub_iter, arg3);
379 *type_ptr = dbus_message_iter_get_arg_type (&sub_iter);
381 /* Got what we wanted. */
382 return true;
386 jack_dbus_error (call, JACK_DBUS_ERROR_INVALID_ARGS,
387 "Invalid arguments to method \"%s\"",
388 call->method_name);
390 return false;
394 * Append a variant type to a D-Bus message.
395 * Return false if something fails, true otherwise.
397 bool
398 jack_dbus_message_append_variant(
399 DBusMessageIter *iter,
400 int type,
401 const char *signature,
402 message_arg_t *arg)
404 DBusMessageIter sub_iter;
406 /* Open a variant container. */
407 if (!dbus_message_iter_open_container (iter, DBUS_TYPE_VARIANT, signature, &sub_iter))
409 goto fail;
412 /* Append the supplied value. */
413 if (!dbus_message_iter_append_basic (&sub_iter, type, (const void *) arg))
415 dbus_message_iter_close_container (iter, &sub_iter);
416 goto fail;
419 /* Close the container. */
420 if (!dbus_message_iter_close_container (iter, &sub_iter))
422 goto fail;
425 return true;
427 fail:
428 return false;
432 * Construct an empty method return message.
434 * The operation can only fail due to lack of memory, in which case
435 * there's no sense in trying to construct an error return. Instead,
436 * call->reply will be set to NULL and handled in send_method_return().
438 void
439 jack_dbus_construct_method_return_empty(
440 struct jack_dbus_method_call * call)
442 call->reply = dbus_message_new_method_return (call->message);
444 if (call->reply == NULL)
446 jack_error ("Ran out of memory trying to construct method return");
451 * Construct a method return which holds a single argument or, if
452 * the type parameter is DBUS_TYPE_INVALID, no arguments at all
453 * (a void message).
455 * The operation can only fail due to lack of memory, in which case
456 * there's no sense in trying to construct an error return. Instead,
457 * call->reply will be set to NULL and handled in send_method_return().
459 void
460 jack_dbus_construct_method_return_single(
461 struct jack_dbus_method_call *call,
462 int type,
463 message_arg_t arg)
465 DBusMessageIter iter;
466 call->reply = dbus_message_new_method_return (call->message);
468 if (call->reply == NULL)
470 goto fail_no_mem;
473 /* Void method return requested by caller. */
474 if (type == DBUS_TYPE_INVALID)
476 return;
479 /* Prevent crash on NULL input string. */
480 else if (type == DBUS_TYPE_STRING && arg.string == NULL)
482 arg.string = "";
485 dbus_message_iter_init_append (call->reply, &iter);
487 if (!dbus_message_iter_append_basic (&iter, type, (const void *) &arg))
489 dbus_message_unref (call->reply);
490 call->reply = NULL;
491 goto fail_no_mem;
494 return;
496 fail_no_mem:
497 jack_error ("Ran out of memory trying to construct method return");
501 * Construct a method return which holds an array of strings.
503 * The operation can only fail due to lack of memory, in which case
504 * there's no sense in trying to construct an error return. Instead,
505 * call->reply will be set to NULL and handled in send_method_return().
507 void
508 jack_dbus_construct_method_return_array_of_strings(
509 struct jack_dbus_method_call *call,
510 unsigned int num_members,
511 const char **array)
513 DBusMessageIter iter, sub_iter;
514 unsigned int i;
516 call->reply = dbus_message_new_method_return (call->message);
517 if (!call->reply)
519 goto fail;
522 dbus_message_iter_init_append (call->reply, &iter);
524 if (!dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "s", &sub_iter))
526 goto fail_unref;
529 for (i = 0; i < num_members; ++i)
531 if (!dbus_message_iter_append_basic (&sub_iter, DBUS_TYPE_STRING, (const void *) &array[i]))
533 dbus_message_iter_close_container (&iter, &sub_iter);
534 goto fail_unref;
538 if (!dbus_message_iter_close_container (&iter, &sub_iter))
540 goto fail_unref;
543 return;
545 fail_unref:
546 dbus_message_unref (call->reply);
547 call->reply = NULL;
549 fail:
550 jack_error ("Ran out of memory trying to construct method return");
553 void
554 jack_dbus_info_callback(const char *msg)
556 time_t timestamp;
557 char timestamp_str[26];
559 time(&timestamp);
560 ctime_r(&timestamp, timestamp_str);
561 timestamp_str[24] = 0;
563 fprintf(g_logfile, "%s: %s\n", timestamp_str, msg);
564 fflush(g_logfile);
567 #define ANSI_BOLD_ON "\033[1m"
568 #define ANSI_BOLD_OFF "\033[22m"
569 #define ANSI_COLOR_RED "\033[31m"
570 #define ANSI_RESET "\033[0m"
572 void
573 jack_dbus_error_callback(const char *msg)
575 time_t timestamp;
576 char timestamp_str[26];
578 time(&timestamp);
579 ctime_r(&timestamp, timestamp_str);
580 timestamp_str[24] = 0;
582 fprintf(g_logfile, "%s: " ANSI_BOLD_ON ANSI_COLOR_RED "ERROR: %s" ANSI_RESET "\n", timestamp_str, msg);
583 fflush(g_logfile);
586 bool
587 ensure_dir_exist(const char *dirname, int mode)
589 struct stat st;
590 if (stat(dirname, &st) != 0)
592 if (errno == ENOENT)
594 printf("Directory \"%s\" does not exist. Creating...\n", dirname);
595 if (mkdir(dirname, mode) != 0)
597 fprintf(stderr, "Failed to create \"%s\" directory: %d (%s)\n", dirname, errno, strerror(errno));
598 return false;
601 else
603 fprintf(stderr, "Failed to stat \"%s\": %d (%s)\n", dirname, errno, strerror(errno));
604 return false;
607 else
609 if (!S_ISDIR(st.st_mode))
611 fprintf(stderr, "\"%s\" exists but is not directory.\n", dirname);
612 return false;
615 return true;
618 char *
619 pathname_cat(const char *pathname_a, const char *pathname_b)
621 char *pathname;
622 int pathname_a_len, pathname_b_len, pathname_len;
623 pathname_a_len = strlen(pathname_a);
624 pathname_b_len = strlen(pathname_b);
625 pathname = malloc(pathname_a_len + pathname_b_len + 1);
626 if (pathname == NULL)
628 fprintf(stderr, "Out of memory\n");
629 return NULL;
631 memcpy(pathname, pathname_a, pathname_a_len);
632 memcpy(pathname + pathname_a_len, pathname_b, pathname_b_len);
633 pathname_len = pathname_a_len + pathname_b_len;
634 pathname[pathname_len] = 0;
635 return pathname;
638 bool
639 paths_init()
641 const char *home_dir, *xdg_config_home, *xdg_log_home;
643 home_dir = getenv("HOME");
644 if (home_dir == NULL)
646 fprintf(stderr, "Environment variable HOME not set\n");
647 goto fail;
650 xdg_config_home = getenv("XDG_CONFIG_HOME");
651 if (xdg_config_home == NULL)
653 if (!(xdg_config_home = pathname_cat(home_dir, DEFAULT_XDG_CONFIG))) goto fail;
656 if (!(xdg_log_home = pathname_cat(home_dir, DEFAULT_XDG_LOG))) goto fail;
658 if (!(g_jackdbus_config_dir = pathname_cat(xdg_config_home, JACKDBUS_DIR))) goto fail;
659 if (!(g_jackdbus_log_dir = pathname_cat(xdg_log_home, JACKDBUS_DIR))) goto fail;
661 if (!ensure_dir_exist(xdg_config_home, 0700))
663 goto fail;
666 if (!ensure_dir_exist(xdg_log_home, 0700))
668 goto fail;
671 if (!ensure_dir_exist(g_jackdbus_config_dir, 0700))
673 free(g_jackdbus_config_dir);
674 goto fail;
676 g_jackdbus_config_dir_len = strlen(g_jackdbus_config_dir);
678 if (!ensure_dir_exist(g_jackdbus_log_dir, 0700))
680 free(g_jackdbus_log_dir);
681 goto fail;
683 g_jackdbus_log_dir_len = strlen(g_jackdbus_log_dir);
685 return true;
687 fail:
688 return false;
691 void
692 paths_uninit()
694 free(g_jackdbus_config_dir);
695 free(g_jackdbus_log_dir);
699 log_init()
701 char *log_filename;
702 size_t log_len;
704 log_len = strlen(JACKDBUS_LOG);
706 log_filename = malloc(g_jackdbus_log_dir_len + log_len + 1);
707 if (log_filename == NULL)
709 fprintf(stderr, "Out of memory\n");
710 return FALSE;
713 memcpy(log_filename, g_jackdbus_log_dir, g_jackdbus_log_dir_len);
714 memcpy(log_filename + g_jackdbus_log_dir_len, JACKDBUS_LOG, log_len);
715 log_filename[g_jackdbus_log_dir_len + log_len] = 0;
717 g_logfile = fopen(log_filename, "a");
718 if (g_logfile == NULL)
720 fprintf(stderr, "Cannot open jackdbus log file \"%s\": %d (%s)\n", log_filename, errno, strerror(errno));
721 free(log_filename);
722 return FALSE;
725 free(log_filename);
727 return TRUE;
730 void
731 log_uninit()
733 fclose(g_logfile);
736 void
737 jack_dbus_error(
738 void *dbus_call_context_ptr,
739 const char *error_name,
740 const char *format,
741 ...)
743 va_list ap;
744 char buffer[300];
746 va_start(ap, format);
748 vsnprintf(buffer, sizeof(buffer), format, ap);
750 jack_error_callback(buffer);
751 if (dbus_call_context_ptr != NULL)
753 if (((struct jack_dbus_method_call *)dbus_call_context_ptr)->reply != NULL)
755 dbus_message_unref(((struct jack_dbus_method_call *)dbus_call_context_ptr)->reply);
756 ((struct jack_dbus_method_call *)dbus_call_context_ptr)->reply = NULL;
759 ((struct jack_dbus_method_call *)dbus_call_context_ptr)->reply = dbus_message_new_error(
760 ((struct jack_dbus_method_call *)dbus_call_context_ptr)->message,
761 error_name,
762 buffer);
765 va_end(ap);
768 void
769 jack_dbus_only_error(
770 void *dbus_call_context_ptr,
771 const char *error_name,
772 const char *format,
773 ...)
775 va_list ap;
776 char buffer[300];
778 va_start(ap, format);
780 vsnprintf(buffer, sizeof(buffer), format, ap);
782 if (((struct jack_dbus_method_call *)dbus_call_context_ptr)->reply != NULL)
784 dbus_message_unref(((struct jack_dbus_method_call *)dbus_call_context_ptr)->reply);
785 ((struct jack_dbus_method_call *)dbus_call_context_ptr)->reply = NULL;
788 ((struct jack_dbus_method_call *)dbus_call_context_ptr)->reply = dbus_message_new_error(
789 ((struct jack_dbus_method_call *)dbus_call_context_ptr)->message,
790 error_name,
791 buffer);
793 va_end(ap);
797 main (int argc, char **argv)
799 DBusError error;
800 int ret;
801 void *controller_ptr;
802 struct stat st;
803 char timestamp_str[26];
805 st.st_mtime = 0;
806 stat(argv[0], &st);
807 ctime_r(&st.st_mtime, timestamp_str);
808 timestamp_str[24] = 0;
810 if (!jack_controller_settings_init())
812 ret = 1;
813 goto fail;
816 if (argc != 2 || strcmp(argv[1], "auto") != 0)
818 ret = 0;
819 fprintf(
820 stderr,
821 "jackdbus should be auto-executed by D-Bus message bus daemon.\n"
822 "If you want to run it manually anyway, specify \"auto\" as only parameter\n");
823 goto fail_uninit_xml;
826 if (!paths_init())
828 ret = 1;
829 goto fail_uninit_xml;
832 if (!log_init())
834 ret = 1;
835 goto fail_uninit_paths;
838 #if !defined(DISABLE_SIGNAL_MAGIC)
839 jackctl_setup_signals(0);
840 #endif
842 jack_set_error_function(jack_dbus_error_callback);
843 jack_set_info_function(jack_dbus_info_callback);
845 /* setup our SIGSEGV magic that prints nice stack in our logfile */
846 setup_sigsegv();
848 jack_info("------------------");
849 jack_info("Controller activated. Version %s (%s) built on %s", jack_get_version_string(), SVN_VERSION, timestamp_str);
851 if (!dbus_threads_init_default())
853 jack_error("dbus_threads_init_default() failed");
854 ret = 1;
855 goto fail_uninit_log;
858 dbus_error_init (&error);
859 g_connection = dbus_bus_get (DBUS_BUS_SESSION, &error);
860 if (dbus_error_is_set (&error))
862 jack_error("Cannot connect to D-Bus session bus: %s", error.message);
863 ret = 1;
864 goto fail_uninit_log;
867 ret = dbus_bus_request_name(
868 g_connection,
869 "org.jackaudio.service",
870 DBUS_NAME_FLAG_DO_NOT_QUEUE,
871 &error);
872 if (ret == -1)
874 jack_error("Cannot request service name: %s", error.message);
875 dbus_error_free(&error);
876 ret = 1;
877 goto fail_unref_connection;
879 else if (ret == DBUS_REQUEST_NAME_REPLY_EXISTS)
881 jack_error("Requested D-Bus service name already exists");
882 ret = 1;
883 goto fail_unref_connection;
886 controller_ptr = jack_controller_create(g_connection);
888 if (controller_ptr == NULL)
890 ret = 1;
891 goto fail_unref_connection;
894 jack_info("Listening for D-Bus messages");
896 g_exit_command = FALSE;
897 while (!g_exit_command && dbus_connection_read_write_dispatch (g_connection, 200));
899 jack_controller_destroy(controller_ptr);
901 jack_info("Controller deactivated.");
903 ret = 0;
905 fail_unref_connection:
906 dbus_connection_unref(g_connection);
908 fail_uninit_log:
909 log_uninit();
911 fail_uninit_paths:
912 paths_uninit();
914 fail_uninit_xml:
915 jack_controller_settings_uninit();
917 fail:
918 return ret;