4 * Copyright (C) 2012 Intel Corporation. All rights reserved.
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU Lesser General Public License,
8 * version 2.1, as published by the Free Software Foundation.
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
19 * Mark Ryan <mark.d.ryan@intel.com>
30 #include <sys/signalfd.h>
33 #include "interface.h"
39 typedef struct msu_context_t_ msu_context_t;
40 struct msu_context_t_ {
46 GDBusNodeInfo *root_node_info;
47 GDBusNodeInfo *server_node_info;
49 GDBusConnection *connection;
53 GCancellable *cancellable;
54 msu_task_t *current_task;
56 msu_settings_context_t *settings;
59 static msu_context_t g_context;
61 static const gchar g_msu_root_introspection[] =
63 " <interface name='"MSU_INTERFACE_MANAGER"'>"
64 " <method name='"MSU_INTERFACE_GET_VERSION"'>"
65 " <arg type='s' name='"MSU_INTERFACE_VERSION"'"
68 " <method name='"MSU_INTERFACE_RELEASE"'>"
70 " <method name='"MSU_INTERFACE_GET_SERVERS"'>"
71 " <arg type='ao' name='"MSU_INTERFACE_SERVERS"'"
74 " <method name='"MSU_INTERFACE_SET_PROTOCOL_INFO"'>"
75 " <arg type='s' name='"MSU_INTERFACE_PROTOCOL_INFO"'"
78 " <method name='"MSU_INTERFACE_PREFER_LOCAL_ADDRESSES"'>"
79 " <arg type='b' name='"MSU_INTERFACE_PREFER"'"
82 " <signal name='"MSU_INTERFACE_FOUND_SERVER"'>"
83 " <arg type='o' name='"MSU_INTERFACE_PATH"'/>"
85 " <signal name='"MSU_INTERFACE_LOST_SERVER"'>"
86 " <arg type='o' name='"MSU_INTERFACE_PATH"'/>"
91 static const gchar g_msu_server_introspection[] =
93 " <interface name='"MSU_INTERFACE_PROPERTIES"'>"
94 " <method name='"MSU_INTERFACE_GET"'>"
95 " <arg type='s' name='"MSU_INTERFACE_INTERFACE_NAME"'"
97 " <arg type='s' name='"MSU_INTERFACE_PROPERTY_NAME"'"
99 " <arg type='v' name='"MSU_INTERFACE_VALUE"'"
102 " <method name='"MSU_INTERFACE_GET_ALL"'>"
103 " <arg type='s' name='"MSU_INTERFACE_INTERFACE_NAME"'"
105 " <arg type='a{sv}' name='"MSU_INTERFACE_PROPERTIES_VALUE"'"
108 " <signal name='"MSU_INTERFACE_PROPERTIES_CHANGED"'>"
109 " <arg type='s' name='"MSU_INTERFACE_INTERFACE_NAME"'/>"
110 " <arg type='a{sv}' name='"MSU_INTERFACE_CHANGED_PROPERTIES"'/>"
111 " <arg type='as' name='"MSU_INTERFACE_INVALIDATED_PROPERTIES"'/>"
114 " <interface name='"MSU_INTERFACE_MEDIA_OBJECT"'>"
115 " <property type='o' name='"MSU_INTERFACE_PROP_PARENT"'"
117 " <property type='s' name='"MSU_INTERFACE_PROP_TYPE"'"
119 " <property type='o' name='"MSU_INTERFACE_PROP_PATH"'"
121 " <property type='s' name='"MSU_INTERFACE_PROP_DISPLAY_NAME"'"
123 " <property type='s' name='"MSU_INTERFACE_PROP_CREATOR"'"
125 " <property type='b' name='"MSU_INTERFACE_PROP_RESTRICTED"'"
127 " <property type='a{sb}' name='"MSU_INTERFACE_PROP_DLNA_MANAGED"'"
129 " <method name='"MSU_INTERFACE_DELETE"'>"
131 " <method name='"MSU_INTERFACE_UPDATE"'>"
132 " <arg type='a{sv}' name='"MSU_INTERFACE_TO_ADD_UPDATE"'"
134 " <arg type='as' name='"MSU_INTERFACE_TO_DELETE"'"
138 " <interface name='"MSU_INTERFACE_MEDIA_CONTAINER"'>"
139 " <method name='"MSU_INTERFACE_LIST_CHILDREN"'>"
140 " <arg type='u' name='"MSU_INTERFACE_OFFSET"'"
142 " <arg type='u' name='"MSU_INTERFACE_MAX"'"
144 " <arg type='as' name='"MSU_INTERFACE_FILTER"'"
146 " <arg type='aa{sv}' name='"MSU_INTERFACE_CHILDREN"'"
149 " <method name='"MSU_INTERFACE_LIST_CHILDREN_EX"'>"
150 " <arg type='u' name='"MSU_INTERFACE_OFFSET"'"
152 " <arg type='u' name='"MSU_INTERFACE_MAX"'"
154 " <arg type='as' name='"MSU_INTERFACE_FILTER"'"
156 " <arg type='s' name='"MSU_INTERFACE_SORT_BY"'"
158 " <arg type='aa{sv}' name='"MSU_INTERFACE_CHILDREN"'"
161 " <method name='"MSU_INTERFACE_LIST_CONTAINERS"'>"
162 " <arg type='u' name='"MSU_INTERFACE_OFFSET"'"
164 " <arg type='u' name='"MSU_INTERFACE_MAX"'"
166 " <arg type='as' name='"MSU_INTERFACE_FILTER"'"
168 " <arg type='aa{sv}' name='"MSU_INTERFACE_CHILDREN"'"
171 " <method name='"MSU_INTERFACE_LIST_CONTAINERS_EX"'>"
172 " <arg type='u' name='"MSU_INTERFACE_OFFSET"'"
174 " <arg type='u' name='"MSU_INTERFACE_MAX"'"
176 " <arg type='as' name='"MSU_INTERFACE_FILTER"'"
178 " <arg type='s' name='"MSU_INTERFACE_SORT_BY"'"
180 " <arg type='aa{sv}' name='"MSU_INTERFACE_CHILDREN"'"
183 " <method name='"MSU_INTERFACE_LIST_ITEMS"'>"
184 " <arg type='u' name='"MSU_INTERFACE_OFFSET"'"
186 " <arg type='u' name='"MSU_INTERFACE_MAX"'"
188 " <arg type='as' name='"MSU_INTERFACE_FILTER"'"
190 " <arg type='aa{sv}' name='"MSU_INTERFACE_CHILDREN"'"
193 " <method name='"MSU_INTERFACE_LIST_ITEMS_EX"'>"
194 " <arg type='u' name='"MSU_INTERFACE_OFFSET"'"
196 " <arg type='u' name='"MSU_INTERFACE_MAX"'"
198 " <arg type='as' name='"MSU_INTERFACE_FILTER"'"
200 " <arg type='s' name='"MSU_INTERFACE_SORT_BY"'"
202 " <arg type='aa{sv}' name='"MSU_INTERFACE_CHILDREN"'"
205 " <method name='"MSU_INTERFACE_SEARCH_OBJECTS"'>"
206 " <arg type='s' name='"MSU_INTERFACE_QUERY"'"
208 " <arg type='u' name='"MSU_INTERFACE_OFFSET"'"
210 " <arg type='u' name='"MSU_INTERFACE_MAX"'"
212 " <arg type='as' name='"MSU_INTERFACE_FILTER"'"
214 " <arg type='aa{sv}' name='"MSU_INTERFACE_CHILDREN"'"
217 " <method name='"MSU_INTERFACE_SEARCH_OBJECTS_EX"'>"
218 " <arg type='s' name='"MSU_INTERFACE_QUERY"'"
220 " <arg type='u' name='"MSU_INTERFACE_OFFSET"'"
222 " <arg type='u' name='"MSU_INTERFACE_MAX"'"
224 " <arg type='as' name='"MSU_INTERFACE_FILTER"'"
226 " <arg type='s' name='"MSU_INTERFACE_SORT_BY"'"
228 " <arg type='aa{sv}' name='"MSU_INTERFACE_CHILDREN"'"
230 " <arg type='u' name='"MSU_INTERFACE_TOTAL_ITEMS"'"
233 " <method name='"MSU_INTERFACE_UPLOAD"'>"
234 " <arg type='s' name='"MSU_INTERFACE_PROP_DISPLAY_NAME"'"
236 " <arg type='s' name='"MSU_INTERFACE_FILE_PATH"'"
238 " <arg type='u' name='"MSU_INTERFACE_UPLOAD_ID"'"
240 " <arg type='o' name='"MSU_INTERFACE_PATH"'"
243 " <method name='"MSU_INTERFACE_CREATE_CONTAINER"'>"
244 " <arg type='s' name='"MSU_INTERFACE_PROP_DISPLAY_NAME"'"
246 " <arg type='s' name='"MSU_INTERFACE_PROP_TYPE"'"
248 " <arg type='as' name='"MSU_INTERFACE_CHILD_TYPES"'"
250 " <arg type='o' name='"MSU_INTERFACE_PATH"'"
253 " <property type='u' name='"MSU_INTERFACE_PROP_CHILD_COUNT"'"
255 " <property type='b' name='"MSU_INTERFACE_PROP_SEARCHABLE"'"
257 " <property type='a(sb)' name='"MSU_INTERFACE_PROP_CREATE_CLASSES"'"
260 " <interface name='"MSU_INTERFACE_MEDIA_ITEM"'>"
261 " <method name='"MSU_INTERFACE_GET_COMPATIBLE_RESOURCE"'>"
262 " <arg type='s' name='"MSU_INTERFACE_PROTOCOL_INFO"'"
264 " <arg type='as' name='"MSU_INTERFACE_FILTER"'"
266 " <arg type='a{sv}' name='"MSU_INTERFACE_PROPERTIES_VALUE"'"
269 " <property type='as' name='"MSU_INTERFACE_PROP_URLS"'"
271 " <property type='s' name='"MSU_INTERFACE_PROP_MIME_TYPE"'"
273 " <property type='s' name='"MSU_INTERFACE_PROP_ARTIST"'"
275 " <property type='as' name='"MSU_INTERFACE_PROP_ARTISTS"'"
277 " <property type='s' name='"MSU_INTERFACE_PROP_ALBUM"'"
279 " <property type='s' name='"MSU_INTERFACE_PROP_DATE"'"
281 " <property type='s' name='"MSU_INTERFACE_PROP_GENRE"'"
283 " <property type='s' name='"MSU_INTERFACE_PROP_DLNA_PROFILE"'"
285 " <property type='i' name='"MSU_INTERFACE_PROP_TRACK_NUMBER"'"
287 " <property type='x' name='"MSU_INTERFACE_PROP_SIZE"'"
289 " <property type='i' name='"MSU_INTERFACE_PROP_DURATION"'"
291 " <property type='i' name='"MSU_INTERFACE_PROP_BITRATE"'"
293 " <property type='i' name='"MSU_INTERFACE_PROP_SAMPLE_RATE"'"
295 " <property type='i' name='"MSU_INTERFACE_PROP_BITS_PER_SAMPLE"'"
297 " <property type='i' name='"MSU_INTERFACE_PROP_WIDTH"'"
299 " <property type='i' name='"MSU_INTERFACE_PROP_HEIGHT"'"
301 " <property type='i' name='"MSU_INTERFACE_PROP_COLOR_DEPTH"'"
303 " <property type='s' name='"MSU_INTERFACE_PROP_ALBUM_ART_URL"'"
305 " <property type='o' name='"MSU_INTERFACE_PROP_REFPATH"'"
307 " <property type='aa{sv}' name='"MSU_INTERFACE_PROP_RESOURCES"'"
310 " <interface name='"MSU_INTERFACE_MEDIA_DEVICE"'>"
311 " <method name='"MSU_INTERFACE_UPLOAD_TO_ANY"'>"
312 " <arg type='s' name='"MSU_INTERFACE_PROP_DISPLAY_NAME"'"
314 " <arg type='s' name='"MSU_INTERFACE_FILE_PATH"'"
316 " <arg type='u' name='"MSU_INTERFACE_UPLOAD_ID"'"
318 " <arg type='o' name='"MSU_INTERFACE_PATH"'"
321 " <method name='"MSU_INTERFACE_GET_UPLOAD_STATUS"'>"
322 " <arg type='u' name='"MSU_INTERFACE_UPLOAD_ID"'"
324 " <arg type='s' name='"MSU_INTERFACE_UPLOAD_STATUS"'"
326 " <arg type='t' name='"MSU_INTERFACE_LENGTH"'"
328 " <arg type='t' name='"MSU_INTERFACE_TOTAL"'"
331 " <method name='"MSU_INTERFACE_GET_UPLOAD_IDS"'>"
332 " <arg type='au' name='"MSU_INTERFACE_TOTAL"'"
335 " <method name='"MSU_INTERFACE_CANCEL_UPLOAD"'>"
336 " <arg type='u' name='"MSU_INTERFACE_UPLOAD_ID"'"
339 " <method name='"MSU_INTERFACE_CREATE_CONTAINER_IN_ANY"'>"
340 " <arg type='s' name='"MSU_INTERFACE_PROP_DISPLAY_NAME"'"
342 " <arg type='s' name='"MSU_INTERFACE_PROP_TYPE"'"
344 " <arg type='as' name='"MSU_INTERFACE_CHILD_TYPES"'"
346 " <arg type='o' name='"MSU_INTERFACE_PATH"'"
349 " <property type='s' name='"MSU_INTERFACE_PROP_LOCATION"'"
351 " <property type='s' name='"MSU_INTERFACE_PROP_UDN"'"
353 " <property type='s' name='"MSU_INTERFACE_PROP_DEVICE_TYPE"'"
355 " <property type='s' name='"MSU_INTERFACE_PROP_FRIENDLY_NAME"'"
357 " <property type='s' name='"MSU_INTERFACE_PROP_MANUFACTURER"'"
359 " <property type='s' name='"MSU_INTERFACE_PROP_MANUFACTURER_URL"'"
361 " <property type='s' name='"MSU_INTERFACE_PROP_MODEL_DESCRIPTION"'"
363 " <property type='s' name='"MSU_INTERFACE_PROP_MODEL_NAME"'"
365 " <property type='s' name='"MSU_INTERFACE_PROP_MODEL_NUMBER"'"
367 " <property type='s' name='"MSU_INTERFACE_PROP_MODEL_URL"'"
369 " <property type='s' name='"MSU_INTERFACE_PROP_SERIAL_NUMBER"'"
371 " <property type='s' name='"MSU_INTERFACE_PROP_PRESENTATION_URL"'"
373 " <property type='s' name='"MSU_INTERFACE_PROP_ICON_URL"'"
375 " <property type='a{sv}'name='"
376 MSU_INTERFACE_PROP_SV_DLNA_CAPABILITIES"'"
378 " <property type='as' name='"
379 MSU_INTERFACE_PROP_SV_SEARCH_CAPABILITIES"'"
381 " <property type='as' name='"
382 MSU_INTERFACE_PROP_SV_SORT_CAPABILITIES"'"
384 " <property type='as' name='"
385 MSU_INTERFACE_PROP_SV_SORT_EXT_CAPABILITIES"'"
387 " <property type='a(ssao)' name='"
388 MSU_INTERFACE_PROP_SV_FEATURE_LIST"'"
390 " <property type='u' name='"
391 MSU_INTERFACE_PROP_ESV_SYSTEM_UPDATE_ID"'"
393 " <property type='s' name='"
394 MSU_INTERFACE_PROP_ESV_SERVICE_RESET_TOKEN"'"
396 " <signal name='"MSU_INTERFACE_CONTAINER_UPDATE"'>"
397 " <arg type='ao' name='"MSU_INTERFACE_CONTAINER_PATHS"'/>"
399 " <signal name='"MSU_INTERFACE_UPLOAD_UPDATE"'>"
400 " <arg type='u' name='"MSU_INTERFACE_UPLOAD_ID"'/>"
401 " <arg type='s' name='"MSU_INTERFACE_UPLOAD_STATUS"'/>"
402 " <arg type='t' name='"MSU_INTERFACE_LENGTH"'/>"
403 " <arg type='t' name='"MSU_INTERFACE_TOTAL"'/>"
408 static gboolean prv_process_task(gpointer user_data);
410 static void prv_free_msu_task_cb(gpointer data, gpointer user_data)
412 msu_task_delete(data);
415 static void prv_process_sync_task(msu_task_t *task)
417 const gchar *client_name;
418 msu_client_t *client;
420 g_context.current_task = task;
422 switch (task->type) {
423 case MSU_TASK_GET_VERSION:
424 msu_task_complete_and_delete(task);
426 case MSU_TASK_GET_SERVERS:
427 task->result = msu_upnp_get_server_ids(g_context.upnp);
428 msu_task_complete_and_delete(task);
430 case MSU_TASK_SET_PROTOCOL_INFO:
432 g_dbus_method_invocation_get_sender(task->invocation);
433 client = g_hash_table_lookup(g_context.watchers, client_name);
435 g_free(client->protocol_info);
436 if (task->ut.protocol_info.protocol_info[0]) {
437 client->protocol_info =
438 task->ut.protocol_info.protocol_info;
439 task->ut.protocol_info.protocol_info = NULL;
441 client->protocol_info = NULL;
444 msu_task_complete_and_delete(task);
446 case MSU_TASK_SET_PREFER_LOCAL_ADDRESSES:
448 g_dbus_method_invocation_get_sender(task->invocation);
449 client = g_hash_table_lookup(g_context.watchers, client_name);
451 client->prefer_local_addresses =
452 task->ut.prefer_local_addresses.prefer;
454 msu_task_complete_and_delete(task);
456 case MSU_TASK_GET_UPLOAD_STATUS:
457 msu_upnp_get_upload_status(g_context.upnp, task);
459 case MSU_TASK_GET_UPLOAD_IDS:
460 msu_upnp_get_upload_ids(g_context.upnp, task);
462 case MSU_TASK_CANCEL_UPLOAD:
463 msu_upnp_cancel_upload(g_context.upnp, task);
469 g_context.current_task = NULL;
472 static void prv_async_task_complete(msu_task_t *task, GVariant *result,
475 MSU_LOG_DEBUG("Enter");
477 g_object_unref(g_context.cancellable);
478 g_context.cancellable = NULL;
479 g_context.current_task = NULL;
482 msu_task_fail_and_delete(task, error);
485 task->result = result;
486 msu_task_complete_and_delete(task);
489 if (g_context.quitting)
490 g_main_loop_quit(g_context.main_loop);
491 else if (g_context.tasks->len > 0)
492 g_context.idle_id = g_idle_add(prv_process_task, NULL);
494 MSU_LOG_DEBUG("Exit");
497 static void prv_process_async_task(msu_task_t *task)
499 const gchar *client_name;
500 msu_client_t *client;
502 MSU_LOG_DEBUG("Enter");
504 g_context.cancellable = g_cancellable_new();
505 g_context.current_task = task;
507 g_dbus_method_invocation_get_sender(task->invocation);
508 client = g_hash_table_lookup(g_context.watchers, client_name);
510 switch (task->type) {
511 case MSU_TASK_GET_CHILDREN:
512 msu_upnp_get_children(g_context.upnp, client, task,
513 g_context.cancellable,
514 prv_async_task_complete);
516 case MSU_TASK_GET_PROP:
517 msu_upnp_get_prop(g_context.upnp, client, task,
518 g_context.cancellable,
519 prv_async_task_complete);
521 case MSU_TASK_GET_ALL_PROPS:
522 msu_upnp_get_all_props(g_context.upnp, client, task,
523 g_context.cancellable,
524 prv_async_task_complete);
526 case MSU_TASK_SEARCH:
527 msu_upnp_search(g_context.upnp, client, task,
528 g_context.cancellable,
529 prv_async_task_complete);
531 case MSU_TASK_GET_RESOURCE:
532 msu_upnp_get_resource(g_context.upnp, client, task,
533 g_context.cancellable,
534 prv_async_task_complete);
536 case MSU_TASK_UPLOAD_TO_ANY:
537 msu_upnp_upload_to_any(g_context.upnp, client, task,
538 g_context.cancellable,
539 prv_async_task_complete);
541 case MSU_TASK_UPLOAD:
542 msu_upnp_upload(g_context.upnp, client, task,
543 g_context.cancellable,
544 prv_async_task_complete);
546 case MSU_TASK_DELETE_OBJECT:
547 msu_upnp_delete_object(g_context.upnp, client, task,
548 g_context.cancellable,
549 prv_async_task_complete);
551 case MSU_TASK_CREATE_CONTAINER:
552 msu_upnp_create_container(g_context.upnp, client, task,
553 g_context.cancellable,
554 prv_async_task_complete);
556 case MSU_TASK_CREATE_CONTAINER_IN_ANY:
557 msu_upnp_create_container_in_any(g_context.upnp, client, task,
558 g_context.cancellable,
559 prv_async_task_complete);
561 case MSU_TASK_UPDATE_OBJECT:
562 msu_upnp_update_object(g_context.upnp, client, task,
563 g_context.cancellable,
564 prv_async_task_complete);
570 MSU_LOG_DEBUG("Exit");
573 static gboolean prv_process_task(gpointer user_data)
576 gboolean retval = FALSE;
578 if (g_context.tasks->len > 0) {
579 task = g_ptr_array_index(g_context.tasks, 0);
580 if (task->synchronous) {
581 prv_process_sync_task(task);
584 prv_process_async_task(task);
585 g_context.idle_id = 0;
587 g_ptr_array_remove_index(g_context.tasks, 0);
589 g_context.idle_id = 0;
595 static void prv_msu_method_call(GDBusConnection *conn,
598 const gchar *interface,
600 GVariant *parameters,
601 GDBusMethodInvocation *invocation,
604 static void prv_object_method_call(GDBusConnection *conn,
607 const gchar *interface,
609 GVariant *parameters,
610 GDBusMethodInvocation *invocation,
613 static void prv_item_method_call(GDBusConnection *conn,
616 const gchar *interface,
618 GVariant *parameters,
619 GDBusMethodInvocation *invocation,
622 static void prv_con_method_call(GDBusConnection *conn,
625 const gchar *interface,
627 GVariant *parameters,
628 GDBusMethodInvocation *invocation,
631 static void prv_props_method_call(GDBusConnection *conn,
634 const gchar *interface,
636 GVariant *parameters,
637 GDBusMethodInvocation *invocation,
640 static void prv_device_method_call(GDBusConnection *conn,
643 const gchar *interface,
645 GVariant *parameters,
646 GDBusMethodInvocation *invocation,
649 static const GDBusInterfaceVTable g_msu_vtable = {
655 static const GDBusInterfaceVTable g_object_vtable = {
656 prv_object_method_call,
661 static const GDBusInterfaceVTable g_item_vtable = {
662 prv_item_method_call,
667 static const GDBusInterfaceVTable g_ms_vtable = {
673 static const GDBusInterfaceVTable g_props_vtable = {
674 prv_props_method_call,
679 static const GDBusInterfaceVTable g_device_vtable = {
680 prv_device_method_call,
685 static const GDBusInterfaceVTable *g_server_vtables[MSU_INTERFACE_INFO_MAX] = {
693 static void prv_msu_context_init(void)
695 memset(&g_context, 0, sizeof(g_context));
698 static void prv_msu_context_free(void)
700 msu_upnp_delete(g_context.upnp);
702 if (g_context.watchers)
703 g_hash_table_unref(g_context.watchers);
705 if (g_context.tasks) {
706 g_ptr_array_foreach(g_context.tasks, prv_free_msu_task_cb,
708 g_ptr_array_unref(g_context.tasks);
711 if (g_context.idle_id)
712 (void) g_source_remove(g_context.idle_id);
714 if (g_context.sig_id)
715 (void) g_source_remove(g_context.sig_id);
717 if (g_context.connection) {
718 if (g_context.msu_id)
719 g_dbus_connection_unregister_object(
720 g_context.connection,
724 if (g_context.owner_id)
725 g_bus_unown_name(g_context.owner_id);
727 if (g_context.connection)
728 g_object_unref(g_context.connection);
730 if (g_context.main_loop)
731 g_main_loop_unref(g_context.main_loop);
733 if (g_context.server_node_info)
734 g_dbus_node_info_unref(g_context.server_node_info);
736 if (g_context.root_node_info)
737 g_dbus_node_info_unref(g_context.root_node_info);
739 if (g_context.settings)
740 msu_settings_delete(g_context.settings);
743 static void prv_quit(void)
745 if (g_context.cancellable) {
746 g_cancellable_cancel(g_context.cancellable);
747 g_context.quitting = TRUE;
749 g_main_loop_quit(g_context.main_loop);
753 static void prv_remove_client(const gchar *name)
755 const gchar *client_name;
759 if (g_context.cancellable) {
760 client_name = g_dbus_method_invocation_get_sender(
761 g_context.current_task->invocation);
762 if (!strcmp(client_name, name)) {
763 MSU_LOG_DEBUG("Cancelling current task, type is %d",
764 g_context.current_task->type);
766 g_cancellable_cancel(g_context.cancellable);
771 while (pos < g_context.tasks->len) {
772 task = (msu_task_t *) g_ptr_array_index(g_context.tasks, pos);
774 client_name = g_dbus_method_invocation_get_sender(
777 if (strcmp(client_name, name)) {
782 MSU_LOG_DEBUG("Removing task type %d from array", task->type);
784 (void) g_ptr_array_remove_index(g_context.tasks, pos);
785 msu_task_cancel_and_delete(task);
788 (void) g_hash_table_remove(g_context.watchers, name);
790 if (g_hash_table_size(g_context.watchers) == 0)
791 if (!msu_settings_is_never_quit(g_context.settings))
795 static void prv_lost_client(GDBusConnection *connection, const gchar *name,
798 MSU_LOG_DEBUG("Lost Client %s", name);
800 prv_remove_client(name);
803 static void prv_add_task(msu_task_t *task)
805 const gchar *client_name;
806 msu_client_t *client;
808 client_name = g_dbus_method_invocation_get_sender(task->invocation);
810 if (!g_hash_table_lookup(g_context.watchers, client_name)) {
811 client = g_new0(msu_client_t, 1);
812 client->prefer_local_addresses = TRUE;
813 client->id = g_bus_watch_name(G_BUS_TYPE_SESSION, client_name,
814 G_BUS_NAME_WATCHER_FLAGS_NONE,
815 NULL, prv_lost_client, NULL,
817 g_hash_table_insert(g_context.watchers, g_strdup(client_name),
821 if (!g_context.cancellable && !g_context.idle_id)
822 g_context.idle_id = g_idle_add(prv_process_task, NULL);
824 g_ptr_array_add(g_context.tasks, task);
827 static void prv_msu_method_call(GDBusConnection *conn,
828 const gchar *sender, const gchar *object,
829 const gchar *interface,
830 const gchar *method, GVariant *parameters,
831 GDBusMethodInvocation *invocation,
834 const gchar *client_name;
837 if (!strcmp(method, MSU_INTERFACE_RELEASE)) {
838 client_name = g_dbus_method_invocation_get_sender(invocation);
839 prv_remove_client(client_name);
840 g_dbus_method_invocation_return_value(invocation, NULL);
841 } else if (!strcmp(method, MSU_INTERFACE_GET_VERSION)) {
842 task = msu_task_get_version_new(invocation);
844 } else if (!strcmp(method, MSU_INTERFACE_GET_SERVERS)) {
845 task = msu_task_get_servers_new(invocation);
847 } else if (!strcmp(method, MSU_INTERFACE_SET_PROTOCOL_INFO)) {
848 task = msu_task_set_protocol_info_new(invocation, parameters);
850 } else if (!strcmp(method, MSU_INTERFACE_PREFER_LOCAL_ADDRESSES)) {
851 task = msu_task_prefer_local_addresses_new(invocation,
857 static void prv_object_method_call(GDBusConnection *conn,
858 const gchar *sender, const gchar *object,
859 const gchar *interface,
860 const gchar *method, GVariant *parameters,
861 GDBusMethodInvocation *invocation,
866 if (!strcmp(method, MSU_INTERFACE_DELETE)) {
867 task = msu_task_delete_new(invocation, object);
868 } else if (!strcmp(method, MSU_INTERFACE_UPDATE))
869 task = msu_task_update_new(invocation, object, parameters);
880 static void prv_item_method_call(GDBusConnection *conn,
881 const gchar *sender, const gchar *object,
882 const gchar *interface,
883 const gchar *method, GVariant *parameters,
884 GDBusMethodInvocation *invocation,
889 if (!strcmp(method, MSU_INTERFACE_GET_COMPATIBLE_RESOURCE)) {
890 task = msu_task_get_resource_new(invocation, object,
897 static void prv_con_method_call(GDBusConnection *conn,
900 const gchar *interface,
902 GVariant *parameters,
903 GDBusMethodInvocation *invocation,
908 if (!strcmp(method, MSU_INTERFACE_LIST_CHILDREN))
909 task = msu_task_get_children_new(invocation, object,
910 parameters, TRUE, TRUE);
911 else if (!strcmp(method, MSU_INTERFACE_LIST_CHILDREN_EX))
912 task = msu_task_get_children_ex_new(invocation, object,
913 parameters, TRUE, TRUE);
914 else if (!strcmp(method, MSU_INTERFACE_LIST_ITEMS))
915 task = msu_task_get_children_new(invocation, object,
916 parameters, TRUE, FALSE);
917 else if (!strcmp(method, MSU_INTERFACE_LIST_ITEMS_EX))
918 task = msu_task_get_children_ex_new(invocation, object,
919 parameters, TRUE, FALSE);
920 else if (!strcmp(method, MSU_INTERFACE_LIST_CONTAINERS))
921 task = msu_task_get_children_new(invocation, object,
922 parameters, FALSE, TRUE);
923 else if (!strcmp(method, MSU_INTERFACE_LIST_CONTAINERS_EX))
924 task = msu_task_get_children_ex_new(invocation, object,
925 parameters, FALSE, TRUE);
926 else if (!strcmp(method, MSU_INTERFACE_SEARCH_OBJECTS))
927 task = msu_task_search_new(invocation, object,
929 else if (!strcmp(method, MSU_INTERFACE_SEARCH_OBJECTS_EX))
930 task = msu_task_search_ex_new(invocation, object,
932 else if (!strcmp(method, MSU_INTERFACE_UPLOAD))
933 task = msu_task_upload_new(invocation, object, parameters);
934 else if (!strcmp(method, MSU_INTERFACE_CREATE_CONTAINER))
935 task = msu_task_create_container_new_generic(invocation,
936 MSU_TASK_CREATE_CONTAINER,
948 static void prv_props_method_call(GDBusConnection *conn,
951 const gchar *interface,
953 GVariant *parameters,
954 GDBusMethodInvocation *invocation,
959 if (!strcmp(method, MSU_INTERFACE_GET_ALL))
960 task = msu_task_get_props_new(invocation, object, parameters);
961 else if (!strcmp(method, MSU_INTERFACE_GET))
962 task = msu_task_get_prop_new(invocation, object, parameters);
973 static void prv_device_method_call(GDBusConnection *conn,
974 const gchar *sender, const gchar *object,
975 const gchar *interface,
976 const gchar *method, GVariant *parameters,
977 GDBusMethodInvocation *invocation,
982 if (!strcmp(method, MSU_INTERFACE_UPLOAD_TO_ANY)) {
983 task = msu_task_upload_to_any_new(invocation, object,
986 } else if (!strcmp(method, MSU_INTERFACE_CREATE_CONTAINER_IN_ANY)) {
987 task = msu_task_create_container_new_generic(invocation,
988 MSU_TASK_CREATE_CONTAINER_IN_ANY,
991 } else if (!strcmp(method, MSU_INTERFACE_GET_UPLOAD_STATUS)) {
992 task = msu_task_get_upload_status_new(invocation, object,
995 } else if (!strcmp(method, MSU_INTERFACE_GET_UPLOAD_IDS)) {
996 task = msu_task_get_upload_ids_new(invocation, object);
998 } else if (!strcmp(method, MSU_INTERFACE_CANCEL_UPLOAD)) {
999 task = msu_task_cancel_upload_new(invocation, object,
1005 static void prv_found_media_server(const gchar *path, void *user_data)
1007 (void) g_dbus_connection_emit_signal(g_context.connection,
1010 MSU_INTERFACE_MANAGER,
1011 MSU_INTERFACE_FOUND_SERVER,
1012 g_variant_new("(o)", path),
1016 static void prv_lost_media_server(const gchar *path, void *user_data)
1018 (void) g_dbus_connection_emit_signal(g_context.connection,
1021 MSU_INTERFACE_MANAGER,
1022 MSU_INTERFACE_LOST_SERVER,
1023 g_variant_new("(o)", path),
1027 static void prv_bus_acquired(GDBusConnection *connection, const gchar *name,
1030 msu_interface_info_t *info;
1033 g_context.connection = connection;
1036 g_dbus_connection_register_object(connection, MSU_OBJECT,
1037 g_context.root_node_info->
1040 user_data, NULL, NULL);
1042 if (!g_context.msu_id) {
1043 g_context.error = true;
1044 g_main_loop_quit(g_context.main_loop);
1046 info = g_new(msu_interface_info_t, MSU_INTERFACE_INFO_MAX);
1047 for (i = 0; i < MSU_INTERFACE_INFO_MAX; ++i) {
1049 g_context.server_node_info->interfaces[i];
1050 info[i].vtable = g_server_vtables[i];
1052 g_context.upnp = msu_upnp_new(connection, info,
1053 prv_found_media_server,
1054 prv_lost_media_server,
1059 static void prv_name_lost(GDBusConnection *connection, const gchar *name,
1062 g_context.connection = NULL;
1067 static gboolean prv_quit_handler(GIOChannel *source, GIOCondition condition,
1071 g_context.sig_id = 0;
1076 static bool prv_init_signal_handler(sigset_t mask)
1078 bool retval = false;
1080 GIOChannel *channel = NULL;
1082 fd = signalfd(-1, &mask, SFD_NONBLOCK);
1086 channel = g_io_channel_unix_new(fd);
1087 g_io_channel_set_close_on_unref(channel, TRUE);
1089 if (g_io_channel_set_flags(channel, G_IO_FLAG_NONBLOCK, NULL) !=
1093 if (g_io_channel_set_encoding(channel, NULL, NULL) !=
1097 g_context.sig_id = g_io_add_watch(channel, G_IO_IN | G_IO_PRI,
1106 g_io_channel_unref(channel);
1111 static void prv_unregister_client(gpointer user_data)
1113 msu_client_t *client = user_data;
1116 g_bus_unwatch_name(client->id);
1117 g_free(client->protocol_info);
1122 int main(int argc, char *argv[])
1127 prv_msu_context_init();
1130 sigaddset(&mask, SIGTERM);
1131 sigaddset(&mask, SIGINT);
1133 if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
1138 msu_log_init(argv[0]);
1139 msu_settings_new(&g_context.settings);
1141 g_context.root_node_info =
1142 g_dbus_node_info_new_for_xml(g_msu_root_introspection, NULL);
1143 if (!g_context.root_node_info)
1146 g_context.server_node_info =
1147 g_dbus_node_info_new_for_xml(g_msu_server_introspection, NULL);
1148 if (!g_context.server_node_info)
1151 g_context.main_loop = g_main_loop_new(NULL, FALSE);
1153 g_context.owner_id = g_bus_own_name(G_BUS_TYPE_SESSION,
1155 G_BUS_NAME_OWNER_FLAGS_NONE,
1156 prv_bus_acquired, NULL,
1157 prv_name_lost, NULL, NULL);
1159 g_context.tasks = g_ptr_array_new();
1161 g_context.watchers = g_hash_table_new_full(g_str_hash, g_str_equal,
1162 g_free, prv_unregister_client);
1164 if (!prv_init_signal_handler(mask))
1167 g_main_loop_run(g_context.main_loop);
1168 if (g_context.error)
1175 prv_msu_context_free();