diff options
-rw-r--r-- | configure.ac | 1 | ||||
-rw-r--r-- | doc/server/dbus/API.txt | 12 | ||||
-rw-r--r-- | libdleyna/server/Makefile.am | 10 | ||||
-rw-r--r-- | libdleyna/server/device.c | 769 | ||||
-rw-r--r-- | libdleyna/server/device.h | 37 | ||||
-rw-r--r-- | libdleyna/server/interface.h | 3 | ||||
-rw-r--r-- | libdleyna/server/props.c | 29 | ||||
-rw-r--r-- | libdleyna/server/props.h | 8 | ||||
-rw-r--r-- | libdleyna/server/server.c | 14 | ||||
-rw-r--r-- | libdleyna/server/task.c | 13 | ||||
-rw-r--r-- | libdleyna/server/task.h | 7 | ||||
-rw-r--r-- | libdleyna/server/upnp.c | 147 | ||||
-rw-r--r-- | libdleyna/server/upnp.h | 8 | ||||
-rw-r--r-- | libdleyna/server/xml-util.c | 133 | ||||
-rw-r--r-- | libdleyna/server/xml-util.h | 35 | ||||
-rw-r--r-- | test/dbus/mediaconsole.py | 3 |
16 files changed, 1006 insertions, 223 deletions
diff --git a/configure.ac b/configure.ac index 355f516..539aa43 100644 --- a/configure.ac +++ b/configure.ac @@ -43,6 +43,7 @@ PKG_CHECK_MODULES([GUPNP], [gupnp-1.0 >= 0.20.3]) PKG_CHECK_MODULES([GUPNPAV], [gupnp-av-1.0 >= 0.11.5]) PKG_CHECK_MODULES([GUPNPDLNA], [gupnp-dlna-2.0 >= 0.9.4]) PKG_CHECK_MODULES([SOUP], [libsoup-2.4 >= 2.28.2]) +PKG_CHECK_MODULES([LIBXML], [libxml-2.0]) # Checks for header files. AC_CHECK_HEADERS([stdlib.h string.h syslog.h]) diff --git a/doc/server/dbus/API.txt b/doc/server/dbus/API.txt index 0804691..2943378 100644 --- a/doc/server/dbus/API.txt +++ b/doc/server/dbus/API.txt @@ -204,6 +204,9 @@ below: |------------------------------------------------------------------------------| | UDN | s | m | The Unique Device Name of the server. | |------------------------------------------------------------------------------| +| RootUDN | s | o | The Unique Device Name of the root | +| | | | device, if the server is a sub-device. | +|------------------------------------------------------------------------------| | FriendlyName | s | m | The friendly name of the media server. | -------------------------------------------------------------------------------| | IconURL | s | o | A URL pointing to an icon that | @@ -265,7 +268,9 @@ below: | SystemUpdateID | u | m | An integer value that is incremenented | | | | | every time changes are made to the DMS. | |------------------------------------------------------------------------------| - +| Sleeping | b | o | An boolean value which represents the | +| | | | server sleeping state. | +|------------------------------------------------------------------------------| (* where m/o indicates whether the property is optional or mandatory ) (1) A value of -1 for the srs-rt-retention-period capability denotes an infinite retention period. @@ -350,6 +355,7 @@ Both RequestedMimeType and Resolution parameters are currently reserved for future use and should be set as an empty string. BrowseObjects(as ObjectPath, as Filter) -> aa{sv} + This method returns properties of all media objects specified by the first parameter. The list of properties to return is specified by the second parameter. @@ -375,6 +381,10 @@ The purposes of this method are: retrieve a subset of an object's properties. Browse is likely to be more efficient than GetAll in such cases. +Wake() -> void + +Sends a magic packet to the server to wake it up if it is in sleeping state. + Signals: --------- diff --git a/libdleyna/server/Makefile.am b/libdleyna/server/Makefile.am index 0c8a6d8..020b41c 100644 --- a/libdleyna/server/Makefile.am +++ b/libdleyna/server/Makefile.am @@ -8,6 +8,7 @@ AM_CFLAGS = $(GLIB_CFLAGS) \ $(GUPNPAV_CFLAGS) \ $(GUPNPDLNA_CFLAGS) \ $(SOUP_CFLAGS) \ + $(LIBXML_CFLAGS) \ -include config.h ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS} @@ -31,7 +32,8 @@ libdleyna_server_1_0_la_SOURCES = $(libdleyna_serverinc_HEADERS) \ search.c \ sort.c \ task.c \ - upnp.c + upnp.c \ + xml-util.c libdleyna_server_1_0_la_LIBADD = $(GLIB_LIBS) \ $(GIO_LIBS) \ @@ -40,7 +42,8 @@ libdleyna_server_1_0_la_LIBADD = $(GLIB_LIBS) \ $(GUPNP_LIBS) \ $(GUPNPAV_LIBS) \ $(GUPNPDLNA_LIBS) \ - $(SOUP_LIBS) + $(SOUP_LIBS) \ + $(LIBXML_LIBS) MAINTAINERCLEANFILES = Makefile.in \ aclocal.m4 \ @@ -66,7 +69,8 @@ EXTRA_DIST = $(sysconf_DATA) \ server.h \ sort.h \ task.h \ - upnp.h + upnp.h \ + xml-util.h CLEANFILES = dleyna-server-service.conf DISTCLEANFILES = dleyna-server-service.conf diff --git a/libdleyna/server/device.c b/libdleyna/server/device.c index 86045f2..d5d5bf8 100644 --- a/libdleyna/server/device.c +++ b/libdleyna/server/device.c @@ -36,12 +36,17 @@ #include "interface.h" #include "path.h" #include "server.h" +#include "xml-util.h" #define DLS_SYSTEM_UPDATE_VAR "SystemUpdateID" #define DLS_CONTAINER_UPDATE_VAR "ContainerUpdateIDs" #define DLS_LAST_CHANGE_VAR "LastChange" +#define DLS_NETWORK_INTERFACE_INFO_VAR "NetworkInterfaceInfo" #define DLS_DMS_DEVICE_TYPE "urn:schemas-upnp-org:device:MediaServer:" - +#define DLS_CONTENT_DIRECTORY_SERVICE_TYPE \ + "urn:schemas-upnp-org:service:ContentDirectory" +#define DLS_ENERGY_MANAGEMENT_SERVICE_TYPE \ + "urn:schemas-upnp-org:service:EnergyManagement:1" #define DLS_UPLOAD_STATUS_IN_PROGRESS "IN_PROGRESS" #define DLS_UPLOAD_STATUS_CANCELLED "CANCELLED" #define DLS_UPLOAD_STATUS_ERROR "ERROR" @@ -122,6 +127,10 @@ static void prv_last_change_cb(GUPnPServiceProxy *proxy, const char *variable, GValue *value, gpointer user_data); +static void prv_network_interface_info_cb(GUPnPServiceProxy *proxy, + const char *variable, + GValue *value, + gpointer user_data); static void prv_upload_delete(gpointer up); static void prv_upload_job_delete(gpointer up); static void prv_get_sr_token_for_props(GUPnPServiceProxy *proxy, @@ -135,6 +144,8 @@ static GUPnPServiceProxyAction *prv_browse_objects_begin_action_cb( GUPnPServiceProxy *proxy, gboolean *failed); +static void prv_free_network_if_info(dls_network_if_info_t *info); + static void prv_object_builder_delete(void *dob) { dls_device_object_builder_t *builder = dob; @@ -163,32 +174,45 @@ static void prv_count_data_new(dls_async_task_t *cb_data, static void prv_context_unsubscribe(dls_device_context_t *ctx) { - if (ctx->timeout_id) { - (void) g_source_remove(ctx->timeout_id); - ctx->timeout_id = 0; + if (ctx->cds.timeout_id) { + (void) g_source_remove(ctx->cds.timeout_id); + ctx->cds.timeout_id = 0; } - if (ctx->subscribed) { - gupnp_service_proxy_remove_notify( - ctx->service_proxy, - DLS_SYSTEM_UPDATE_VAR, - prv_system_update_cb, - ctx->device); - gupnp_service_proxy_remove_notify( - ctx->service_proxy, - DLS_CONTAINER_UPDATE_VAR, - prv_container_update_cb, - ctx->device); + if (ctx->ems.timeout_id) { + (void) g_source_remove(ctx->ems.timeout_id); + ctx->ems.timeout_id = 0; + } + + if (ctx->cds.subscribed) { + gupnp_service_proxy_remove_notify(ctx->cds.proxy, + DLS_SYSTEM_UPDATE_VAR, + prv_system_update_cb, + ctx->device); + gupnp_service_proxy_remove_notify(ctx->cds.proxy, + DLS_CONTAINER_UPDATE_VAR, + prv_container_update_cb, + ctx->device); + gupnp_service_proxy_remove_notify(ctx->cds.proxy, + DLS_LAST_CHANGE_VAR, + prv_last_change_cb, + ctx->device); + + gupnp_service_proxy_set_subscribed(ctx->cds.proxy, FALSE); + + ctx->cds.subscribed = FALSE; + } + + if (ctx->ems.subscribed) { gupnp_service_proxy_remove_notify( - ctx->service_proxy, - DLS_LAST_CHANGE_VAR, - prv_last_change_cb, - ctx->device); + ctx->ems.proxy, + DLS_NETWORK_INTERFACE_INFO_VAR, + prv_network_interface_info_cb, + ctx->device); - gupnp_service_proxy_set_subscribed(ctx->service_proxy, - FALSE); + gupnp_service_proxy_set_subscribed(ctx->ems.proxy, FALSE); - ctx->subscribed = FALSE; + ctx->ems.subscribed = FALSE; } } @@ -199,35 +223,94 @@ static void prv_context_delete(gpointer context) if (ctx) { prv_context_unsubscribe(ctx); + if (ctx->device_info) + g_object_unref(ctx->device_info); + if (ctx->device_proxy) g_object_unref(ctx->device_proxy); - if (ctx->service_proxy) - g_object_unref(ctx->service_proxy); + prv_free_network_if_info(ctx->network_if_info); + + if (ctx->cds.proxy) + g_object_unref(ctx->cds.proxy); + + if (ctx->ems.proxy) + g_object_unref(ctx->ems.proxy); g_free(ctx->ip_address); g_free(ctx); } } +static GUPnPServiceInfo *prv_lookup_em_service(GUPnPDeviceInfo *device_info) +{ + GList *child_devices; + GList *next; + GUPnPDeviceInfo *child_info = NULL; + GUPnPServiceInfo *service_info = NULL; + + child_devices = gupnp_device_info_list_devices(device_info); + + next = child_devices; + while (next != NULL) { + child_info = (GUPnPDeviceInfo *)next->data; + + service_info = gupnp_device_info_get_service(child_info, + DLS_ENERGY_MANAGEMENT_SERVICE_TYPE); + + if (service_info != NULL) + break; + + service_info = prv_lookup_em_service(child_info); + + if (service_info != NULL) + break; + + next = g_list_next(next); + } + + g_list_free_full(child_devices, g_object_unref); + + return service_info; +} + static void prv_context_new(const gchar *ip_address, GUPnPDeviceProxy *proxy, + GUPnPDeviceInfo *device_info, dls_device_t *device, dls_device_context_t **context) { - const gchar *service_type = - "urn:schemas-upnp-org:service:ContentDirectory"; dls_device_context_t *ctx = g_new(dls_device_context_t, 1); ctx->ip_address = g_strdup(ip_address); ctx->device_proxy = proxy; + ctx->device_info = device_info; + ctx->device = device; + ctx->cds.subscribed = FALSE; + ctx->cds.timeout_id = 0; + ctx->ems.subscribed = FALSE; + ctx->ems.timeout_id = 0; + + ctx->network_if_info = NULL; + g_object_ref(proxy); - ctx->service_proxy = (GUPnPServiceProxy *) - gupnp_device_info_get_service((GUPnPDeviceInfo *)proxy, - service_type); - ctx->subscribed = FALSE; - ctx->timeout_id = 0; + g_object_ref(device_info); + + ctx->cds.proxy = (GUPnPServiceProxy *) + gupnp_device_info_get_service( + device_info, + DLS_CONTENT_DIRECTORY_SERVICE_TYPE); + + ctx->ems.proxy = (GUPnPServiceProxy *) + gupnp_device_info_get_service( + (GUPnPDeviceInfo *)proxy, + DLS_ENERGY_MANAGEMENT_SERVICE_TYPE); + + if (ctx->ems.proxy == NULL) + ctx->ems.proxy = (GUPnPServiceProxy *) + prv_lookup_em_service( + (GUPnPDeviceInfo *)proxy); *context = ctx; } @@ -459,6 +542,254 @@ on_error: g_error_free(error); } +static void prv_free_network_if_info(dls_network_if_info_t *info) +{ + if (info != NULL) { + g_free(info->mac_address); + g_free(info->device_uuid); + g_free(info->network_if_mode); + g_free(info->wake_on_pattern); + g_free(info->wake_transport); + g_list_free_full(info->ip_addresses, g_free); + + g_free(info); + } +} + +static dls_network_if_info_t *prv_get_network_if_info(xmlNode *device_if_node) +{ + dls_network_if_info_t *info = NULL; + GList *ipv4_addresses; + GList *ipv6_addresses; + + info = g_new0(dls_network_if_info_t, 1); + + ipv4_addresses = xml_util_get_child_string_list_content_by_name( + device_if_node, + "NetworkInterface", + "AssociatedIpAddresses", + "Ipv4", NULL); + + ipv6_addresses = xml_util_get_child_string_list_content_by_name( + device_if_node, + "NetworkInterface", + "AssociatedIpAddresses", + "Ipv6", NULL); + + info->ip_addresses = g_list_concat(ipv4_addresses, ipv6_addresses); + + info->device_uuid = xml_util_get_child_string_content_by_name( + device_if_node, + "DeviceUUID", NULL); + + info->mac_address = xml_util_get_child_string_content_by_name( + device_if_node, + "NetworkInterface", + "MacAddress", NULL); + + info->network_if_mode = xml_util_get_child_string_content_by_name( + device_if_node, + "NetworkInterface", + "NetworkInterfaceMode" + , NULL); + + info->wake_on_pattern = xml_util_get_child_string_content_by_name( + device_if_node, + "NetworkInterface", + "WakeOnPattern", NULL); + + info->wake_transport = xml_util_get_child_string_content_by_name( + device_if_node, + "NetworkInterface", + "WakeSupportedTransport", NULL); + + if ((info->device_uuid == NULL || strlen(info->device_uuid) > 70) || + (info->mac_address == NULL || strlen(info->mac_address) != 17) || + (info->network_if_mode == NULL) || (info->ip_addresses == NULL) || + (info->wake_on_pattern == NULL) || (info->wake_transport == NULL)) + goto on_error; + + return info; + +on_error: + prv_free_network_if_info(info); + + return NULL; +} + +static GList *prv_network_if_info_decode(const gchar *info) +{ + xmlDoc *doc; + xmlNode *node; + GList *info_list = NULL; + dls_network_if_info_t *if_info; + + DLEYNA_LOG_DEBUG("Enter"); + + DLEYNA_LOG_DEBUG_NL(); + DLEYNA_LOG_DEBUG("NetworkInterfaceInfo XML: %s", info); + DLEYNA_LOG_DEBUG_NL(); + + doc = xmlParseMemory(info, strlen(info) + 1); + if (doc == NULL) { + DLEYNA_LOG_WARNING("XML: invalid document"); + + goto on_exit; + } + + node = xmlDocGetRootElement(doc); + if (node == NULL) { + DLEYNA_LOG_WARNING("XML: empty document"); + + goto on_exit; + } + + if (node->name == NULL) { + DLEYNA_LOG_WARNING("XML: empty document name"); + + goto on_exit; + } + + if (strcmp((char *)node->name, "NetworkInterfaceInfo")) { + DLEYNA_LOG_WARNING("XML: invalid document name"); + + goto on_exit; + } + + for (node = node->children; node; node = node->next) { + if (node->name != NULL && + !strcmp((char *)node->name, "DeviceInterface")) { + if_info = prv_get_network_if_info(node); + + if (if_info != NULL) + info_list = g_list_prepend(info_list, if_info); + } + } + +on_exit: + DLEYNA_LOG_DEBUG("Exit"); + + if (doc != NULL) + xmlFreeDoc(doc); + + return info_list; +} + +static gboolean prv_lookup_device_ctx_network_if_info(dls_device_context_t *ctx, + dls_network_if_info_t *info, + gboolean *sleeping) +{ + gboolean found = FALSE; + const gchar *udn; + gchar *ip_address; + GList *next; + + next = info->ip_addresses; + while (next != NULL) { + ip_address = (gchar *)next->data; + if (!strcmp(ctx->ip_address, ip_address)) { + udn = gupnp_device_info_get_udn((GUPnPDeviceInfo *) + ctx->device_proxy); + if (!strcmp(info->device_uuid, udn)) { + found = TRUE; + if (!strcmp(info->network_if_mode, "IP-up")) + *sleeping = FALSE; + else + *sleeping = TRUE; + } + } + + if (found) + break; + + next = g_list_next(next); + } + + return found; +} + +static gboolean prv_get_device_sleeping_state(dls_device_t *device, + const gchar *network_if_info_xml, + gboolean *sleeping) +{ + dls_network_if_info_t *info; + GList *info_list; + GList *next; + unsigned int i; + dls_device_context_t *ctx; + gboolean found = FALSE; + + info_list = prv_network_if_info_decode(network_if_info_xml); + if (info_list == NULL) + goto on_exit; + + next = info_list; + while (next != NULL) { + info = (dls_network_if_info_t *)next->data; + for (i = 0; i < device->contexts->len; ++i) { + ctx = g_ptr_array_index(device->contexts, i); + found = prv_lookup_device_ctx_network_if_info(ctx, + info, + sleeping); + if (found) + break; + } + + next = g_list_next(next); + + if (found) { + prv_free_network_if_info(ctx->network_if_info); + + ctx->network_if_info = info; + + info_list = g_list_remove(info_list, info); + + break; + } + } + + g_list_free_full(info_list, (GDestroyNotify)prv_free_network_if_info); + +on_exit: + + return found; +} + +static void prv_network_interface_info_cb(GUPnPServiceProxy *proxy, + const char *variable, + GValue *value, + gpointer user_data) +{ + dls_device_t *device = user_data; + GVariantBuilder *array; + GVariant *val; + gboolean sleeping; + + if (prv_get_device_sleeping_state(device, + g_value_get_string(value), + &sleeping)) { + device->sleeping = sleeping; + + array = g_variant_builder_new(G_VARIANT_TYPE("a{sv}")); + g_variant_builder_add(array, "{sv}", + DLS_INTERFACE_PROP_SLEEPING, + g_variant_new_boolean(sleeping)); + val = g_variant_new("(s@a{sv}as)", + DLEYNA_SERVER_INTERFACE_MEDIA_DEVICE, + g_variant_builder_end(array), + NULL); + + (void) dls_server_get_connector()->notify(device->connection, + device->path, + DLS_INTERFACE_PROPERTIES, + DLS_INTERFACE_PROPERTIES_CHANGED, + val, + NULL); + + g_variant_builder_unref(array); + } +} + static void prv_build_container_update_array(const gchar *root_path, const gchar *value, GVariantBuilder *builder) @@ -599,49 +930,82 @@ static void prv_system_update_cb(GUPnPServiceProxy *proxy, g_variant_builder_unref(array); } -static gboolean prv_re_enable_subscription(gpointer user_data) +static gboolean prv_re_enable_cd_subscription(gpointer user_data) { dls_device_context_t *context = user_data; - context->timeout_id = 0; + context->cds.timeout_id = 0; return FALSE; } -static void prv_subscription_lost_cb(GUPnPServiceProxy *proxy, +static void prv_cd_subscription_lost_cb(GUPnPServiceProxy *proxy, const GError *reason, gpointer user_data) { dls_device_context_t *context = user_data; - if (!context->timeout_id) { - gupnp_service_proxy_set_subscribed(context->service_proxy, - TRUE); - context->timeout_id = g_timeout_add_seconds( + if (!context->cds.timeout_id) { + gupnp_service_proxy_set_subscribed(context->cds.proxy, TRUE); + context->cds.timeout_id = g_timeout_add_seconds( 10, - prv_re_enable_subscription, + prv_re_enable_cd_subscription, context); } else { - g_source_remove(context->timeout_id); - gupnp_service_proxy_remove_notify(context->service_proxy, + g_source_remove(context->cds.timeout_id); + gupnp_service_proxy_remove_notify(context->cds.proxy, DLS_SYSTEM_UPDATE_VAR, prv_system_update_cb, context->device); - gupnp_service_proxy_remove_notify(context->service_proxy, + gupnp_service_proxy_remove_notify(context->cds.proxy, DLS_CONTAINER_UPDATE_VAR, prv_container_update_cb, context->device); - gupnp_service_proxy_remove_notify(context->service_proxy, + gupnp_service_proxy_remove_notify(context->cds.proxy, DLS_LAST_CHANGE_VAR, prv_last_change_cb, context->device); - context->timeout_id = 0; - context->subscribed = FALSE; + context->cds.timeout_id = 0; + context->cds.subscribed = FALSE; + } +} + +static gboolean prv_re_enable_em_subscription(gpointer user_data) +{ + dls_device_context_t *context = user_data; + + context->cds.timeout_id = 0; + + return FALSE; +} + +static void prv_em_subscription_lost_cb(GUPnPServiceProxy *proxy, + const GError *reason, + gpointer user_data) +{ + dls_device_context_t *context = user_data; + + if (!context->ems.timeout_id) { + gupnp_service_proxy_set_subscribed(context->ems.proxy, TRUE); + context->ems.timeout_id = g_timeout_add_seconds( + 10, + prv_re_enable_em_subscription, + context); + } else { + g_source_remove(context->ems.timeout_id); + gupnp_service_proxy_remove_notify( + context->ems.proxy, + DLS_NETWORK_INTERFACE_INFO_VAR, + prv_network_interface_info_cb, + context->device); + + context->ems.timeout_id = 0; + context->ems.subscribed = FALSE; } } -void dls_device_subscribe_to_contents_change(dls_device_t *device) +void dls_device_subscribe_to_service_changes(dls_device_t *device) { dls_device_context_t *context; @@ -650,31 +1014,47 @@ void dls_device_subscribe_to_contents_change(dls_device_t *device) DLEYNA_LOG_DEBUG("Subscribe for events on context: %s", context->ip_address); - gupnp_service_proxy_add_notify(context->service_proxy, - DLS_SYSTEM_UPDATE_VAR, - G_TYPE_UINT, - prv_system_update_cb, - device); - - gupnp_service_proxy_add_notify(context->service_proxy, - DLS_CONTAINER_UPDATE_VAR, - G_TYPE_STRING, - prv_container_update_cb, - device); + if (context->cds.proxy) { + gupnp_service_proxy_add_notify(context->cds.proxy, + DLS_SYSTEM_UPDATE_VAR, + G_TYPE_UINT, + prv_system_update_cb, + device); + + gupnp_service_proxy_add_notify(context->cds.proxy, + DLS_CONTAINER_UPDATE_VAR, + G_TYPE_STRING, + prv_container_update_cb, + device); + + gupnp_service_proxy_add_notify(context->cds.proxy, + DLS_LAST_CHANGE_VAR, + G_TYPE_STRING, + prv_last_change_cb, + device); + + context->cds.subscribed = TRUE; + gupnp_service_proxy_set_subscribed(context->cds.proxy, TRUE); + + g_signal_connect(context->cds.proxy, "subscription-lost", + G_CALLBACK(prv_cd_subscription_lost_cb), + context); + } - gupnp_service_proxy_add_notify(context->service_proxy, - DLS_LAST_CHANGE_VAR, - G_TYPE_STRING, - prv_last_change_cb, - device); + if (context->ems.proxy) { + gupnp_service_proxy_add_notify(context->ems.proxy, + DLS_NETWORK_INTERFACE_INFO_VAR, + G_TYPE_STRING, + prv_network_interface_info_cb, + device); - context->subscribed = TRUE; - gupnp_service_proxy_set_subscribed(context->service_proxy, TRUE); + context->ems.subscribed = TRUE; + gupnp_service_proxy_set_subscribed(context->ems.proxy, TRUE); - g_signal_connect(context->service_proxy, - "subscription-lost", - G_CALLBACK(prv_subscription_lost_cb), - context); + g_signal_connect(context->ems.proxy, "subscription-lost", + G_CALLBACK(prv_em_subscription_lost_cb), + context); + } } static void prv_feature_list_add_feature(gchar *root_path, @@ -1039,7 +1419,7 @@ static GUPnPServiceProxyAction *prv_subscribe(dleyna_service_task_t *task, device = (dls_device_t *)dleyna_service_task_get_user_data(task); device->construct_step++; - dls_device_subscribe_to_contents_change(device); + dls_device_subscribe_to_service_changes(device); *failed = FALSE; @@ -1141,7 +1521,7 @@ void dls_device_construct( priv_t->vtable = dispatch_table; priv_t->property_map = property_map; - s_proxy = context->service_proxy; + s_proxy = context->cds.proxy; if (dev->construct_step < 1) dleyna_service_task_add(queue_id, prv_get_search_capabilities, @@ -1179,6 +1559,7 @@ void dls_device_construct( dls_device_t *dls_device_new( dleyna_connector_id_t connection, GUPnPDeviceProxy *proxy, + GUPnPDeviceInfo *device_info, const gchar *ip_address, const dleyna_connector_dispatch_cb_t *dispatch_table, GHashTable *property_map, @@ -1200,7 +1581,8 @@ dls_device_t *dls_device_new( dev->contexts = g_ptr_array_new_with_free_func(prv_context_delete); dev->path = new_path; - context = dls_device_append_new_context(dev, ip_address, proxy); + context = dls_device_append_new_context(dev, ip_address, + proxy, device_info); dls_device_construct(dev, context, connection, dispatch_table, property_map, queue_id); @@ -1209,12 +1591,13 @@ dls_device_t *dls_device_new( } dls_device_context_t *dls_device_append_new_context(dls_device_t *device, - const gchar *ip_address, - GUPnPDeviceProxy *proxy) + const gchar *ip_address, + GUPnPDeviceProxy *proxy, + GUPnPDeviceInfo *device_info) { dls_device_context_t *context; - prv_context_new(ip_address, proxy, device, &context); + prv_context_new(ip_address, proxy, device_info, device, &context); g_ptr_array_add(device->contexts, context); return context; @@ -1495,8 +1878,13 @@ void dls_device_get_children(dls_client_t *client, context = dls_device_get_context(task->target.device, client); + cb_data->proxy = context->cds.proxy; + + g_object_add_weak_pointer((G_OBJECT(context->cds.proxy)), + (gpointer *)&cb_data->proxy); + cb_data->action = - gupnp_service_proxy_begin_action(context->service_proxy, + gupnp_service_proxy_begin_action(cb_data->proxy, "Browse", prv_get_children_cb, cb_data, @@ -1517,11 +1905,6 @@ void dls_device_get_children(dls_client_t *client, sort_by, NULL); - cb_data->proxy = context->service_proxy; - - g_object_add_weak_pointer((G_OBJECT(context->service_proxy)), - (gpointer *)&cb_data->proxy); - cb_data->cancel_id = g_cancellable_connect( cb_data->cancellable, G_CALLBACK(dls_async_task_cancelled_cb), @@ -1645,7 +2028,7 @@ static void prv_get_all(GUPnPDIDLLiteParser *parser, } } -static gboolean prv_subscribed(const dls_device_t *device) +static gboolean prv_cds_subscribed(const dls_device_t *device) { dls_device_context_t *context; unsigned int i; @@ -1653,7 +2036,7 @@ static gboolean prv_subscribed(const dls_device_t *device) for (i = 0; i < device->contexts->len; ++i) { context = g_ptr_array_index(device->contexts, i); - if (context->subscribed) { + if (context->cds.subscribed) { subscribed = TRUE; break; } @@ -1712,7 +2095,7 @@ static void prv_get_system_update_id_for_prop(GUPnPServiceProxy *proxy, DLEYNA_LOG_DEBUG("Enter"); - if (prv_subscribed(device)) { + if (prv_cds_subscribed(device)) { suid = device->system_update_id; cb_data->task.result = g_variant_ref_sink( @@ -1805,7 +2188,7 @@ static void prv_get_system_update_id_for_props(GUPnPServiceProxy *proxy, DLEYNA_LOG_DEBUG("Enter"); - if (prv_subscribed(device)) { + if (prv_cds_subscribed(device)) { suid = device->system_update_id; cb_task_data = &cb_data->ut.get_all; @@ -2135,6 +2518,7 @@ static void prv_get_all_ms2spec_props_cb(GUPnPServiceProxy *proxy, goto no_complete; } else if (cb_data->task.type == DLS_TASK_GET_ALL_PROPS && cb_task_data->device_object) { + prv_get_system_update_id_for_props(proxy, cb_data->task.target.device, cb_data); @@ -2193,7 +2577,7 @@ static void prv_get_all_ms2spec_props(dls_device_context_t *context, } cb_data->action = gupnp_service_proxy_begin_action( - context->service_proxy, "Browse", + context->cds.proxy, "Browse", prv_get_all_ms2spec_props_cb, cb_data, "ObjectID", G_TYPE_STRING, task->target.id, "BrowseFlag", G_TYPE_STRING, "BrowseMetadata", @@ -2203,9 +2587,9 @@ static void prv_get_all_ms2spec_props(dls_device_context_t *context, "SortCriteria", G_TYPE_STRING, "", NULL); - cb_data->proxy = context->service_proxy; + cb_data->proxy = context->cds.proxy; - g_object_add_weak_pointer((G_OBJECT(context->service_proxy)), + g_object_add_weak_pointer((G_OBJECT(context->cds.proxy)), (gpointer *)&cb_data->proxy); cb_data->cancel_id = g_cancellable_connect( @@ -2246,15 +2630,16 @@ void dls_device_get_all_props(dls_client_t *client, if (!strcmp(task_data->interface_name, DLEYNA_SERVER_INTERFACE_MEDIA_DEVICE)) { if (root_object) { - dls_props_add_device( - (GUPnPDeviceInfo *)context->device_proxy, - task->target.device, - cb_task_data->vb); - + dls_props_add_device((GUPnPDeviceInfo *) + context->device_proxy, + context->device_info, + context->ems.proxy, + task->target.device, + cb_task_data->vb); prv_get_system_update_id_for_props( - context->service_proxy, - task->target.device, - cb_data); + context->cds.proxy, + task->target.device, + cb_data); } else { cb_data->error = g_error_new(DLEYNA_SERVER_ERROR, @@ -2269,11 +2654,12 @@ void dls_device_get_all_props(dls_client_t *client, prv_get_all_ms2spec_props(context, cb_data); } else { if (root_object) - dls_props_add_device( - (GUPnPDeviceInfo *)context->device_proxy, - task->target.device, - cb_task_data->vb); - + dls_props_add_device((GUPnPDeviceInfo *) + context->device_proxy, + context->device_info, + context->ems.proxy, + task->target.device, + cb_task_data->vb); prv_get_all_ms2spec_props(context, cb_data); } @@ -2599,8 +2985,13 @@ static void prv_get_ms2spec_prop(dls_device_context_t *context, goto on_error; } + cb_data->proxy = context->cds.proxy; + + g_object_add_weak_pointer((G_OBJECT(context->cds.proxy)), + (gpointer *)&cb_data->proxy); + cb_data->action = gupnp_service_proxy_begin_action( - context->service_proxy, "Browse", + cb_data->proxy, "Browse", prv_get_ms2spec_prop_cb, cb_data, "ObjectID", G_TYPE_STRING, cb_data->task.target.id, @@ -2613,11 +3004,6 @@ static void prv_get_ms2spec_prop(dls_device_context_t *context, "", NULL); - cb_data->proxy = context->service_proxy; - - g_object_add_weak_pointer((G_OBJECT(context->service_proxy)), - (gpointer *)&cb_data->proxy); - cb_data->cancel_id = g_cancellable_connect( cb_data->cancellable, G_CALLBACK(dls_async_task_cancelled_cb), @@ -2656,23 +3042,25 @@ void dls_device_get_prop(dls_client_t *client, task_data->prop_name, DLS_INTERFACE_PROP_ESV_SYSTEM_UPDATE_ID)) { prv_get_system_update_id_for_prop( - context->service_proxy, + context->cds.proxy, task->target.device, cb_data); } else if (!strcmp( task_data->prop_name, DLS_INTERFACE_PROP_SV_SERVICE_RESET_TOKEN)) { prv_get_sr_token_for_prop( - context->service_proxy, + context->cds.proxy, task->target.device, cb_data); } else { cb_data->task.result = dls_props_get_device_prop( - (GUPnPDeviceInfo *) - context->device_proxy, - task->target.device, - task_data->prop_name); + (GUPnPDeviceInfo *) + context->device_proxy, + context->device_info, + context->ems.proxy, + task->target.device, + task_data->prop_name); if (!cb_data->task.result) cb_data->error = g_error_new( @@ -2702,7 +3090,7 @@ void dls_device_get_prop(dls_client_t *client, task_data->prop_name, DLS_INTERFACE_PROP_ESV_SYSTEM_UPDATE_ID)) { prv_get_system_update_id_for_prop( - context->service_proxy, + context->cds.proxy, task->target.device, cb_data); complete = TRUE; @@ -2710,17 +3098,20 @@ void dls_device_get_prop(dls_client_t *client, task_data->prop_name, DLS_INTERFACE_PROP_SV_SERVICE_RESET_TOKEN)) { prv_get_sr_token_for_prop( - context->service_proxy, + context->cds.proxy, task->target.device, cb_data); complete = TRUE; } else { cb_data->task.result = - dls_props_get_device_prop( + dls_props_get_device_prop( (GUPnPDeviceInfo *) context->device_proxy, + context->device_info, + context->ems.proxy, task->target.device, task_data->prop_name); + if (cb_data->task.result) { (void) g_idle_add( dls_async_task_complete, @@ -2919,8 +3310,13 @@ void dls_device_search(dls_client_t *client, context = dls_device_get_context(task->target.device, client); + cb_data->proxy = context->cds.proxy; + + g_object_add_weak_pointer((G_OBJECT(context->cds.proxy)), + (gpointer *)&cb_data->proxy); + cb_data->action = gupnp_service_proxy_begin_action( - context->service_proxy, "Search", + cb_data->proxy, "Search", prv_search_cb, cb_data, "ContainerID", G_TYPE_STRING, task->target.id, @@ -2931,11 +3327,6 @@ void dls_device_search(dls_client_t *client, "SortCriteria", G_TYPE_STRING, sort_by, NULL); - cb_data->proxy = context->service_proxy; - - g_object_add_weak_pointer((G_OBJECT(context->service_proxy)), - (gpointer *)&cb_data->proxy); - cb_data->cancel_id = g_cancellable_connect( cb_data->cancellable, G_CALLBACK(dls_async_task_cancelled_cb), @@ -3383,7 +3774,7 @@ void dls_device_browse_objects(dls_client_t *client, dls_task_t *task) dleyna_task_queue_set_user_data(queue_id, task); context = dls_device_get_context(task->target.device, client); - cb_data->proxy = context->service_proxy; + cb_data->proxy = context->cds.proxy; cb_task_data = &cb_data->ut.browse_objects; cb_task_data->queue_id = queue_id; @@ -3391,7 +3782,7 @@ void dls_device_browse_objects(dls_client_t *client, dls_task_t *task) cb_task_data->objects_id = objs; cb_task_data->object_count = length; - g_object_add_weak_pointer((G_OBJECT(context->service_proxy)), + g_object_add_weak_pointer((G_OBJECT(context->cds.proxy)), (gpointer *)&cb_data->proxy); cb_data->cancel_id = g_cancellable_connect( @@ -3428,8 +3819,13 @@ void dls_device_get_resource(dls_client_t *client, cb_task_data->prop_func = G_CALLBACK(prv_get_resource); cb_task_data->device_object = FALSE; + cb_data->proxy = context->cds.proxy; + + g_object_add_weak_pointer((G_OBJECT(context->cds.proxy)), + (gpointer *)&cb_data->proxy); + cb_data->action = gupnp_service_proxy_begin_action( - context->service_proxy, "Browse", + cb_data->proxy, "Browse", prv_get_all_ms2spec_props_cb, cb_data, "ObjectID", G_TYPE_STRING, task->target.id, "BrowseFlag", G_TYPE_STRING, "BrowseMetadata", @@ -3439,11 +3835,6 @@ void dls_device_get_resource(dls_client_t *client, "SortCriteria", G_TYPE_STRING, "", NULL); - cb_data->proxy = context->service_proxy; - - g_object_add_weak_pointer((G_OBJECT(context->service_proxy)), - (gpointer *)&cb_data->proxy); - cb_data->cancel_id = g_cancellable_connect( cb_data->cancellable, G_CALLBACK(dls_async_task_cancelled_cb), @@ -4127,18 +4518,18 @@ void dls_device_upload(dls_client_t *client, DLEYNA_LOG_DEBUG("DIDL: %s", didl); DLEYNA_LOG_DEBUG_NL(); + cb_data->proxy = context->cds.proxy; + + g_object_add_weak_pointer((G_OBJECT(context->cds.proxy)), + (gpointer *)&cb_data->proxy); + cb_data->action = gupnp_service_proxy_begin_action( - context->service_proxy, "CreateObject", + cb_data->proxy, "CreateObject", prv_create_object_upload_cb, cb_data, "ContainerID", G_TYPE_STRING, parent_id, "Elements", G_TYPE_STRING, didl, NULL); - cb_data->proxy = context->service_proxy; - - g_object_add_weak_pointer((G_OBJECT(context->service_proxy)), - (gpointer *)&cb_data->proxy); - cb_data->cancel_id = g_cancellable_connect( cb_data->cancellable, G_CALLBACK(dls_async_task_cancelled_cb), @@ -4280,17 +4671,17 @@ void dls_device_delete_object(dls_client_t *client, context = dls_device_get_context(task->target.device, client); + cb_data->proxy = context->cds.proxy; + + g_object_add_weak_pointer((G_OBJECT(context->cds.proxy)), + (gpointer *)&cb_data->proxy); + cb_data->action = gupnp_service_proxy_begin_action( - context->service_proxy, "DestroyObject", + cb_data->proxy, "DestroyObject", prv_destroy_object_cb, cb_data, "ObjectID", G_TYPE_STRING, task->target.id, NULL); - cb_data->proxy = context->service_proxy; - - g_object_add_weak_pointer((G_OBJECT(context->service_proxy)), - (gpointer *)&cb_data->proxy); - cb_data->cancel_id = g_cancellable_connect(cb_data->cancellable, G_CALLBACK(dls_async_task_cancelled_cb), cb_data, NULL); @@ -4322,18 +4713,18 @@ void dls_device_create_container(dls_client_t *client, DLEYNA_LOG_DEBUG("DIDL: %s", didl); + cb_data->proxy = context->cds.proxy; + + g_object_add_weak_pointer((G_OBJECT(context->cds.proxy)), + (gpointer *)&cb_data->proxy); + cb_data->action = gupnp_service_proxy_begin_action( - context->service_proxy, "CreateObject", + cb_data->proxy, "CreateObject", prv_create_container_cb, cb_data, "ContainerID", G_TYPE_STRING, parent_id, "Elements", G_TYPE_STRING, didl, NULL); - cb_data->proxy = context->service_proxy; - - g_object_add_weak_pointer((G_OBJECT(context->service_proxy)), - (gpointer *)&cb_data->proxy); - cb_data->cancel_id = g_cancellable_connect( cb_data->cancellable, G_CALLBACK(dls_async_task_cancelled_cb), @@ -4670,8 +5061,13 @@ void dls_device_update_object(dls_client_t *client, context = dls_device_get_context(task->target.device, client); + cb_data->proxy = context->cds.proxy; + + g_object_add_weak_pointer((G_OBJECT(context->cds.proxy)), + (gpointer *)&cb_data->proxy); + cb_data->action = gupnp_service_proxy_begin_action( - context->service_proxy, "Browse", + cb_data->proxy, "Browse", prv_update_object_browse_cb, cb_data, "ObjectID", G_TYPE_STRING, task->target.id, "BrowseFlag", G_TYPE_STRING, "BrowseMetadata", @@ -4681,11 +5077,6 @@ void dls_device_update_object(dls_client_t *client, "SortCriteria", G_TYPE_STRING, "", NULL); - cb_data->proxy = context->service_proxy; - - g_object_add_weak_pointer((G_OBJECT(context->service_proxy)), - (gpointer *)&cb_data->proxy); - cb_data->cancel_id = g_cancellable_connect(cb_data->cancellable, G_CALLBACK(dls_async_task_cancelled_cb), cb_data, NULL); @@ -4750,8 +5141,13 @@ void dls_device_get_object_metadata(dls_client_t *client, context = dls_device_get_context(task->target.device, client); + cb_data->proxy = context->cds.proxy; + + g_object_add_weak_pointer((G_OBJECT(context->cds.proxy)), + (gpointer *)&cb_data->proxy); + cb_data->action = gupnp_service_proxy_begin_action( - context->service_proxy, "Browse", + cb_data->proxy, "Browse", prv_get_object_metadata_cb, cb_data, "ObjectID", G_TYPE_STRING, task->target.id, "BrowseFlag", G_TYPE_STRING, "BrowseMetadata", @@ -4761,11 +5157,6 @@ void dls_device_get_object_metadata(dls_client_t *client, "SortCriteria", G_TYPE_STRING, "", NULL); - cb_data->proxy = context->service_proxy; - - g_object_add_weak_pointer((G_OBJECT(context->service_proxy)), - (gpointer *)&cb_data->proxy); - cb_data->cancel_id = g_cancellable_connect(cb_data->cancellable, G_CALLBACK(dls_async_task_cancelled_cb), cb_data, NULL); @@ -4852,18 +5243,18 @@ void dls_device_create_reference(dls_client_t *client, context = dls_device_get_context(task->target.device, client); + cb_data->proxy = context->cds.proxy; + + g_object_add_weak_pointer((G_OBJECT(context->cds.proxy)), + (gpointer *)&cb_data->proxy); + cb_data->action = gupnp_service_proxy_begin_action( - context->service_proxy, "CreateReference", + cb_data->proxy, "CreateReference", prv_create_reference_cb, cb_data, "ContainerID", G_TYPE_STRING, task->target.id, "ObjectID", G_TYPE_STRING, i_id, NULL); - cb_data->proxy = context->service_proxy; - - g_object_add_weak_pointer((G_OBJECT(context->service_proxy)), - (gpointer *)&cb_data->proxy); - cb_data->cancel_id = g_cancellable_connect( cb_data->cancellable, G_CALLBACK(dls_async_task_cancelled_cb), @@ -4949,7 +5340,6 @@ out: void dls_device_get_icon(dls_client_t *client, dls_task_t *task) { - GUPnPDeviceInfo *info; dls_device_context_t *context; dls_async_task_t *cb_data = (dls_async_task_t *)task; dls_device_t *device = task->target.device; @@ -4962,9 +5352,9 @@ void dls_device_get_icon(dls_client_t *client, } context = dls_device_get_context(device, client); - info = (GUPnPDeviceInfo *)context->device_proxy; - url = gupnp_device_info_get_icon_url(info, NULL, -1, -1, -1, FALSE, + url = gupnp_device_info_get_icon_url(context->device_info, + NULL, -1, -1, -1, FALSE, &device->icon.mime_type, NULL, NULL, NULL); if (url == NULL) { @@ -5008,3 +5398,46 @@ end: (void) g_idle_add(dls_async_task_complete, cb_data); } + +void dls_device_wake(dls_client_t *client, dls_task_t *task) +{ + dls_device_context_t *context; + dls_async_task_t *cb_data = (dls_async_task_t *)task; + dls_device_t *device = task->target.device; + dls_network_if_info_t *info; + GList *next; + + DLEYNA_LOG_DEBUG("Enter"); + + context = dls_device_get_context(device, client); + + if ((context->ems.proxy == NULL) || + (context->network_if_info == NULL)) { + cb_data->error = g_error_new(DLEYNA_SERVER_ERROR, + DLEYNA_ERROR_NOT_SUPPORTED, + "WOL is not supported"); + goto end; + } + + info = context->network_if_info; + + DLEYNA_LOG_DEBUG("MacAddress = %s", info->mac_address); + DLEYNA_LOG_DEBUG("DeviceUUID = %s", info->device_uuid); + DLEYNA_LOG_DEBUG("NetworkInterfaceMode = %s", info->network_if_mode); + DLEYNA_LOG_DEBUG("WakeOnPattern = %s", info->wake_on_pattern); + DLEYNA_LOG_DEBUG("WakeSupportedTransport = %s", info->wake_transport); + + next = info->ip_addresses; + while (next != NULL) { + DLEYNA_LOG_DEBUG("IpAddress = %s", (gchar *)next->data); + + next = g_list_next(next); + } + + DLEYNA_LOG_DEBUG("context IpAddress = %s", context->ip_address); + +end: + (void) g_idle_add(dls_async_task_complete, cb_data); + + DLEYNA_LOG_DEBUG("Exit"); +} diff --git a/libdleyna/server/device.h b/libdleyna/server/device.h index 6771464..891351c 100644 --- a/libdleyna/server/device.h +++ b/libdleyna/server/device.h @@ -32,13 +32,32 @@ #include "client.h" #include "props.h" +typedef struct dls_network_if_info_t_ dls_network_if_info_t; +struct dls_network_if_info_t_ { + gchar *system_name; + gchar *mac_address; + gchar *device_uuid; + gchar *network_if_mode; + gchar *wake_on_pattern; + gchar *wake_transport; + GList *ip_addresses; +}; + +typedef struct dls_service_t_ dls_service_t; +struct dls_service_t_ { + GUPnPServiceProxy *proxy; + gboolean subscribed; + guint timeout_id; +}; + struct dls_device_context_t_ { gchar *ip_address; GUPnPDeviceProxy *device_proxy; - GUPnPServiceProxy *service_proxy; + GUPnPDeviceInfo *device_info; dls_device_t *device; - gboolean subscribed; - guint timeout_id; + dls_service_t cds; + dls_service_t ems; + dls_network_if_info_t *network_if_info; }; typedef struct dls_device_icon_t_ dls_device_icon_t; @@ -66,11 +85,13 @@ struct dls_device_t_ { gboolean has_last_change; guint construct_step; dls_device_icon_t icon; + gboolean sleeping; }; dls_device_context_t *dls_device_append_new_context(dls_device_t *device, - const gchar *ip_address, - GUPnPDeviceProxy *proxy); + const gchar *ip_address, + GUPnPDeviceProxy *proxy, + GUPnPDeviceInfo *device_info); void dls_device_delete(void *device); void dls_device_unsubscribe(void *device); @@ -86,6 +107,7 @@ void dls_device_construct( dls_device_t *dls_device_new( dleyna_connector_id_t connection, GUPnPDeviceProxy *proxy, + GUPnPDeviceInfo *device_info, const gchar *ip_address, const dleyna_connector_dispatch_cb_t *dispatch_table, GHashTable *filter_map, @@ -120,7 +142,7 @@ void dls_device_get_resource(dls_client_t *client, dls_task_t *task, const gchar *upnp_filter); -void dls_device_subscribe_to_contents_change(dls_device_t *device); +void dls_device_subscribe_to_service_changes(dls_device_t *device); void dls_device_upload(dls_client_t *client, dls_task_t *task, const gchar *parent_id); @@ -152,4 +174,7 @@ void dls_device_create_reference(dls_client_t *client, void dls_device_get_icon(dls_client_t *client, dls_task_t *task); +void dls_device_wake(dls_client_t *client, + dls_task_t *task); + #endif /* DLS_DEVICE_H__ */ diff --git a/libdleyna/server/interface.h b/libdleyna/server/interface.h index 3a2a6a4..f955db2 100644 --- a/libdleyna/server/interface.h +++ b/libdleyna/server/interface.h @@ -85,6 +85,7 @@ enum dls_interface_type_ { /* Device Properties */ #define DLS_INTERFACE_PROP_LOCATION "Location" #define DLS_INTERFACE_PROP_UDN "UDN" +#define DLS_INTERFACE_PROP_ROOT_UDN "RootUDN" #define DLS_INTERFACE_PROP_DEVICE_TYPE "DeviceType" #define DLS_INTERFACE_PROP_FRIENDLY_NAME "FriendlyName" #define DLS_INTERFACE_PROP_MANUFACTURER "Manufacturer" @@ -96,6 +97,7 @@ enum dls_interface_type_ { #define DLS_INTERFACE_PROP_SERIAL_NUMBER "SerialNumber" #define DLS_INTERFACE_PROP_PRESENTATION_URL "PresentationURL" #define DLS_INTERFACE_PROP_ICON_URL "IconURL" +#define DLS_INTERFACE_PROP_SLEEPING "Sleeping" #define DLS_INTERFACE_PROP_SV_DLNA_CAPABILITIES "DLNACaps" #define DLS_INTERFACE_PROP_SV_SEARCH_CAPABILITIES "SearchCaps" #define DLS_INTERFACE_PROP_SV_SORT_CAPABILITIES "SortCaps" @@ -215,6 +217,7 @@ enum dls_interface_type_ { #define DLS_INTERFACE_ICON_BYTES "Bytes" #define DLS_INTERFACE_MIME_TYPE "MimeType" #define DLS_INTERFACE_REQ_MIME_TYPE "RequestedMimeType" +#define DLS_INTERFACE_WAKE "Wake" #define DLS_INTERFACE_GET_METADATA "GetMetaData" #define DLS_INTERFACE_METADATA "MetaData" diff --git a/libdleyna/server/props.c b/libdleyna/server/props.c index c63ce30..4196e68 100644 --- a/libdleyna/server/props.c +++ b/libdleyna/server/props.c @@ -715,7 +715,9 @@ static GVariant *prv_get_artists_prop(GList *list) return g_variant_builder_end(&vb); } -void dls_props_add_device(GUPnPDeviceInfo *proxy, +void dls_props_add_device(GUPnPDeviceInfo *root_proxy, + GUPnPDeviceInfo *proxy, + GUPnPServiceProxy *ems_proxy, const dls_device_t *device, GVariantBuilder *vb) { @@ -729,6 +731,10 @@ void dls_props_add_device(GUPnPDeviceInfo *proxy, prv_add_string_prop(vb, DLS_INTERFACE_PROP_UDN, gupnp_device_info_get_udn(proxy)); + if (proxy != root_proxy) + prv_add_string_prop(vb, DLS_INTERFACE_PROP_ROOT_UDN, + gupnp_device_info_get_udn(root_proxy)); + prv_add_string_prop(vb, DLS_INTERFACE_PROP_DEVICE_TYPE, gupnp_device_info_get_device_type(proxy)); @@ -802,9 +808,15 @@ void dls_props_add_device(GUPnPDeviceInfo *proxy, g_variant_builder_add(vb, "{sv}", DLS_INTERFACE_PROP_SV_FEATURE_LIST, device->feature_list); + + if (ems_proxy != NULL) + prv_add_bool_prop(vb, DLS_INTERFACE_PROP_SLEEPING, + device->sleeping); } -GVariant *dls_props_get_device_prop(GUPnPDeviceInfo *proxy, +GVariant *dls_props_get_device_prop(GUPnPDeviceInfo *root_proxy, + GUPnPDeviceInfo *proxy, + GUPnPServiceProxy *ems_proxy, const dls_device_t *device, const gchar *prop) { @@ -818,6 +830,9 @@ GVariant *dls_props_get_device_prop(GUPnPDeviceInfo *proxy, str = gupnp_device_info_get_location(proxy); } else if (!strcmp(DLS_INTERFACE_PROP_UDN, prop)) { str = gupnp_device_info_get_udn(proxy); + } else if (!strcmp(DLS_INTERFACE_PROP_ROOT_UDN, prop)) { + if (proxy != root_proxy) + str = gupnp_device_info_get_udn(root_proxy); } else if (!strcmp(DLS_INTERFACE_PROP_DEVICE_TYPE, prop)) { str = gupnp_device_info_get_device_type(proxy); } else if (!strcmp(DLS_INTERFACE_PROP_FRIENDLY_NAME, prop)) { @@ -900,6 +915,16 @@ GVariant *dls_props_get_device_prop(GUPnPDeviceInfo *proxy, DLEYNA_LOG_DEBUG("Prop %s = %s", prop, copy); #endif } + } else if (!strcmp(DLS_INTERFACE_PROP_SLEEPING, prop)) { + if (ems_proxy != NULL) { + retval = g_variant_ref_sink( + g_variant_new_boolean(device->sleeping)); + } + +#if DLEYNA_LOG_LEVEL & DLEYNA_LOG_LEVEL_DEBUG + DLEYNA_LOG_DEBUG("Prop %s = %s", prop, + device->sleeping ? "TRUE":"FALSE"); +#endif } if (!retval) { diff --git a/libdleyna/server/props.h b/libdleyna/server/props.h index 72cff1b..41f66b0 100644 --- a/libdleyna/server/props.h +++ b/libdleyna/server/props.h @@ -93,11 +93,15 @@ gboolean dls_props_parse_update_filter(GHashTable *filter_map, dls_upnp_prop_mask *mask, gchar **upnp_filter); -void dls_props_add_device(GUPnPDeviceInfo *proxy, +void dls_props_add_device(GUPnPDeviceInfo *root_proxy, + GUPnPDeviceInfo *proxy, + GUPnPServiceProxy *ems_proxy, const dls_device_t *device, GVariantBuilder *vb); -GVariant *dls_props_get_device_prop(GUPnPDeviceInfo *proxy, +GVariant *dls_props_get_device_prop(GUPnPDeviceInfo *root_proxy, + GUPnPDeviceInfo *proxy, + GUPnPServiceProxy *ems_proxy, const dls_device_t *device, const gchar *prop); diff --git a/libdleyna/server/server.c b/libdleyna/server/server.c index 5a30500..5367252 100644 --- a/libdleyna/server/server.c +++ b/libdleyna/server/server.c @@ -439,6 +439,8 @@ static const gchar g_server_introspection[] = " </method>" " <method name='"DLS_INTERFACE_CANCEL"'>" " </method>" + " <method name='"DLS_INTERFACE_WAKE"'>" + " </method>" " <method name='"DLS_INTERFACE_GET_ICON"'>" " <arg type='s' name='"DLS_INTERFACE_REQ_MIME_TYPE"'" " direction='in'/>" @@ -483,6 +485,8 @@ static const gchar g_server_introspection[] = " access='read'/>" " <property type='s' name='"DLS_INTERFACE_PROP_ICON_URL"'" " access='read'/>" + " <property type='b' name='"DLS_INTERFACE_PROP_SLEEPING"'" + " access='read'/>" " <property type='a{sv}'name='" DLS_INTERFACE_PROP_SV_DLNA_CAPABILITIES"'" " access='read'/>" @@ -547,7 +551,7 @@ static void prv_process_sync_task(dls_task_t *task) dls_task_complete(task); break; case DLS_TASK_GET_SERVERS: - task->result = dls_upnp_get_server_ids(g_context.upnp); + task->result = dls_upnp_get_device_ids(g_context.upnp); dls_task_complete(task); break; case DLS_TASK_RESCAN: @@ -699,6 +703,10 @@ static void prv_process_async_task(dls_task_t *task) dls_upnp_get_icon(g_context.upnp, client, task, prv_async_task_complete); break; + case DLS_TASK_WAKE: + dls_upnp_wake(g_context.upnp, client, task, + prv_async_task_complete); + break; default: break; } @@ -934,7 +942,7 @@ gboolean dls_server_get_object_info(const gchar *object_path, } *device = dls_device_from_path(*root_path, - dls_upnp_get_server_udn_map(g_context.upnp)); + dls_upnp_get_device_udn_map(g_context.upnp)); if (*device == NULL) { DLEYNA_LOG_WARNING("Cannot locate device for %s", *root_path); @@ -1185,6 +1193,8 @@ static void prv_device_method_call(dleyna_connector_id_t conn, } else if (!strcmp(method, DLS_INTERFACE_BROWSE_OBJECTS)) { task = dls_task_browse_objects_new(invocation, object, parameters, &error); + } else if (!strcmp(method, DLS_INTERFACE_WAKE)) { + task = dls_task_wake_new(invocation, object, &error); } else if (!strcmp(method, DLS_INTERFACE_CANCEL)) { task = NULL; diff --git a/libdleyna/server/task.c b/libdleyna/server/task.c index 1ad4108..312efc0 100644 --- a/libdleyna/server/task.c +++ b/libdleyna/server/task.c @@ -97,6 +97,8 @@ static void prv_delete(dls_task_t *task) g_free(task->ut.get_icon.resolution); g_free(task->ut.get_icon.mime_type); break; + case DLS_TASK_WAKE: + break; default: break; } @@ -658,6 +660,17 @@ finished: return task; } +dls_task_t *dls_task_wake_new(dleyna_connector_msg_id_t invocation, + const gchar *path, GError **error) +{ + dls_task_t *task; + + task = prv_m2spec_task_new(DLS_TASK_WAKE, invocation, path, + NULL, error, FALSE); + + return task; +} + void dls_task_complete(dls_task_t *task) { GVariant *variant = NULL; diff --git a/libdleyna/server/task.h b/libdleyna/server/task.h index a06b3e2..6642e8d 100644 --- a/libdleyna/server/task.h +++ b/libdleyna/server/task.h @@ -57,7 +57,8 @@ enum dls_task_type_t_ { DLS_TASK_GET_ICON, DLS_TASK_MANAGER_GET_ALL_PROPS, DLS_TASK_MANAGER_GET_PROP, - DLS_TASK_MANAGER_SET_PROP + DLS_TASK_MANAGER_SET_PROP, + DLS_TASK_WAKE }; typedef enum dls_task_type_t_ dls_task_type_t; @@ -309,6 +310,10 @@ dls_task_t *dls_task_manager_set_prop_new(dleyna_connector_msg_id_t invocation, GVariant *parameters, GError **error); +dls_task_t *dls_task_wake_new(dleyna_connector_msg_id_t invocation, + const gchar *path, + GError **error); + void dls_task_cancel(dls_task_t *task); void dls_task_complete(dls_task_t *task); diff --git a/libdleyna/server/upnp.c b/libdleyna/server/upnp.c index 68338e6..7301e61 100644 --- a/libdleyna/server/upnp.c +++ b/libdleyna/server/upnp.c @@ -38,6 +38,8 @@ #include "sort.h" #include "upnp.h" +#define DLS_DMS_DEVICE_TYPE "urn:schemas-upnp-org:device:MediaServer:" + struct dls_upnp_t_ { dleyna_connector_id_t connection; const dleyna_connector_dispatch_cb_t *interface_info; @@ -47,8 +49,8 @@ struct dls_upnp_t_ { dls_upnp_callback_t lost_server; GUPnPContextManager *context_manager; void *user_data; - GHashTable *server_udn_map; - GHashTable *server_uc_map; + GHashTable *device_udn_map; + GHashTable *device_uc_map; guint counter; }; @@ -84,13 +86,13 @@ static void prv_device_chain_end(gboolean cancelled, gpointer data) goto on_clear; DLEYNA_LOG_DEBUG("Notify new server available: %s", device->path); - g_hash_table_insert(priv_t->upnp->server_udn_map, g_strdup(priv_t->udn), + g_hash_table_insert(priv_t->upnp->device_udn_map, g_strdup(priv_t->udn), device); priv_t->upnp->found_server(device->path, priv_t->upnp->user_data); on_clear: - g_hash_table_remove(priv_t->upnp->server_uc_map, priv_t->udn); + g_hash_table_remove(priv_t->upnp->device_uc_map, priv_t->udn); if (cancelled) dls_device_delete(device); @@ -106,7 +108,7 @@ static void prv_device_context_switch_end(gboolean cancelled, gpointer data) DLEYNA_LOG_DEBUG("Enter"); - g_hash_table_remove(priv_t->upnp->server_uc_map, priv_t->udn); + g_hash_table_remove(priv_t->upnp->device_uc_map, priv_t->udn); prv_device_new_free(priv_t); DLEYNA_LOG_DEBUG("Exit"); @@ -146,10 +148,49 @@ static void prv_update_device_context(prv_device_new_ct_t *priv_t, priv_t->queue_id = queue_id; priv_t->device = device; - g_hash_table_insert(upnp->server_uc_map, g_strdup(udn), priv_t); + g_hash_table_insert(upnp->device_uc_map, g_strdup(udn), priv_t); +} + +static GUPnPDeviceInfo *prv_lookup_dms_child_device(GUPnPDeviceInfo *proxy) +{ + GList *child_devices; + GList *next; + const gchar *device_type; + GUPnPDeviceInfo *info = NULL; + GUPnPDeviceInfo *child_info = NULL; + + child_devices = gupnp_device_info_list_device_types(proxy); + + next = child_devices; + while (next != NULL) { + device_type = (gchar *)next->data; + + child_info = gupnp_device_info_get_device(proxy, device_type); + + if (g_str_has_prefix(device_type, DLS_DMS_DEVICE_TYPE)) { + break; + } else { + info = prv_lookup_dms_child_device(child_info); + + g_object_unref(child_info); + child_info = NULL; + + if (info != NULL) { + child_info = info; + + break; + } + } + + next = g_list_next(next); + } + + g_list_free_full(child_devices, (GDestroyNotify)g_free); + + return child_info; } -static void prv_server_available_cb(GUPnPControlPoint *cp, +static void prv_device_available_cb(GUPnPControlPoint *cp, GUPnPDeviceProxy *proxy, gpointer user_data) { @@ -161,8 +202,11 @@ static void prv_server_available_cb(GUPnPControlPoint *cp, const dleyna_task_queue_key_t *queue_id; unsigned int i; prv_device_new_ct_t *priv_t; + GUPnPDeviceInfo *device_proxy = (GUPnPDeviceInfo *)proxy; + GUPnPDeviceInfo *device_info = NULL; + const gchar *device_type; - udn = gupnp_device_info_get_udn((GUPnPDeviceInfo *)proxy); + udn = gupnp_device_info_get_udn(device_proxy); ip_address = gupnp_context_get_host_ip( gupnp_control_point_get_context(cp)); @@ -173,10 +217,21 @@ static void prv_server_available_cb(GUPnPControlPoint *cp, DLEYNA_LOG_DEBUG("UDN %s", udn); DLEYNA_LOG_DEBUG("IP Address %s", ip_address); - device = g_hash_table_lookup(upnp->server_udn_map, udn); + device_type = gupnp_device_info_get_device_type(device_proxy); + + if (!g_str_has_prefix(device_type, DLS_DMS_DEVICE_TYPE)) { + device_info = prv_lookup_dms_child_device(device_proxy); + + if (device_info == NULL) + goto on_error; + } else { + device_info = device_proxy; + } + + device = g_hash_table_lookup(upnp->device_udn_map, udn); if (!device) { - priv_t = g_hash_table_lookup(upnp->server_uc_map, udn); + priv_t = g_hash_table_lookup(upnp->device_uc_map, udn); if (priv_t) device = priv_t->device; @@ -188,7 +243,10 @@ static void prv_server_available_cb(GUPnPControlPoint *cp, queue_id = prv_create_device_queue(&priv_t); - device = dls_device_new(upnp->connection, proxy, ip_address, + device = dls_device_new(upnp->connection, + proxy, + device_info, + ip_address, upnp->interface_info, upnp->property_map, upnp->counter, queue_id); @@ -208,8 +266,10 @@ static void prv_server_available_cb(GUPnPControlPoint *cp, if (i == device->contexts->len) { DLEYNA_LOG_DEBUG("Adding Context"); - (void) dls_device_append_new_context(device, ip_address, - proxy); + (void) dls_device_append_new_context(device, + ip_address, + proxy, + device_info); } DLEYNA_LOG_DEBUG_NL(); @@ -220,17 +280,17 @@ on_error: return; } -static gboolean prv_subscribe_to_contents_change(gpointer user_data) +static gboolean prv_subscribe_to_service_changes(gpointer user_data) { dls_device_t *device = user_data; device->timeout_id = 0; - dls_device_subscribe_to_contents_change(device); + dls_device_subscribe_to_service_changes(device); return FALSE; } -static void prv_server_unavailable_cb(GUPnPControlPoint *cp, +static void prv_device_unavailable_cb(GUPnPControlPoint *cp, GUPnPDeviceProxy *proxy, gpointer user_data) { @@ -259,10 +319,10 @@ static void prv_server_unavailable_cb(GUPnPControlPoint *cp, DLEYNA_LOG_DEBUG("UDN %s", udn); DLEYNA_LOG_DEBUG("IP Address %s", ip_address); - device = g_hash_table_lookup(upnp->server_udn_map, udn); + device = g_hash_table_lookup(upnp->device_udn_map, udn); if (!device) { - priv_t = g_hash_table_lookup(upnp->server_uc_map, udn); + priv_t = g_hash_table_lookup(upnp->device_uc_map, udn); if (priv_t) { device = priv_t->device; @@ -284,7 +344,7 @@ static void prv_server_unavailable_cb(GUPnPControlPoint *cp, if (i >= device->contexts->len) goto on_error; - subscribed = context->subscribed; + subscribed = (context->cds.subscribed || context->ems.subscribed); if (under_construction) construction_ctx = !strcmp(context->ip_address, priv_t->ip_address); @@ -295,7 +355,7 @@ static void prv_server_unavailable_cb(GUPnPControlPoint *cp, if (!under_construction) { DLEYNA_LOG_DEBUG("Last Context lost. Delete device"); upnp->lost_server(device->path, upnp->user_data); - g_hash_table_remove(upnp->server_udn_map, udn); + g_hash_table_remove(upnp->device_udn_map, udn); } else { DLEYNA_LOG_WARNING( "Device under construction. Cancelling"); @@ -307,7 +367,7 @@ static void prv_server_unavailable_cb(GUPnPControlPoint *cp, "Device under construction. Switching context"); /* Cancel previous contruction task chain */ - g_hash_table_remove(priv_t->upnp->server_uc_map, priv_t->udn); + g_hash_table_remove(priv_t->upnp->device_uc_map, priv_t->udn); dleyna_task_queue_set_finally(priv_t->queue_id, prv_device_context_switch_end); dleyna_task_processor_cancel_queue(priv_t->queue_id); @@ -330,7 +390,7 @@ static void prv_server_unavailable_cb(GUPnPControlPoint *cp, DLEYNA_LOG_DEBUG("Subscribe on new context"); device->timeout_id = g_timeout_add_seconds(1, - prv_subscribe_to_contents_change, + prv_subscribe_to_service_changes, device); } @@ -351,13 +411,13 @@ static void prv_on_context_available(GUPnPContextManager *context_manager, cp = gupnp_control_point_new( context, - "urn:schemas-upnp-org:device:MediaServer:1"); + "upnp:rootdevice"); g_signal_connect(cp, "device-proxy-available", - G_CALLBACK(prv_server_available_cb), upnp); + G_CALLBACK(prv_device_available_cb), upnp); g_signal_connect(cp, "device-proxy-unavailable", - G_CALLBACK(prv_server_unavailable_cb), upnp); + G_CALLBACK(prv_device_unavailable_cb), upnp); gssdp_resource_browser_set_active(GSSDP_RESOURCE_BROWSER(cp), TRUE); gupnp_context_manager_manage_control_point(upnp->context_manager, cp); @@ -378,11 +438,11 @@ dls_upnp_t *dls_upnp_new(dleyna_connector_id_t connection, upnp->found_server = found_server; upnp->lost_server = lost_server; - upnp->server_udn_map = g_hash_table_new_full(g_str_hash, g_str_equal, + upnp->device_udn_map = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, dls_device_delete); - upnp->server_uc_map = g_hash_table_new_full(g_str_hash, g_str_equal, + upnp->device_uc_map = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); dls_prop_maps_new(&upnp->property_map, &upnp->filter_map); @@ -402,13 +462,13 @@ void dls_upnp_delete(dls_upnp_t *upnp) g_object_unref(upnp->context_manager); g_hash_table_unref(upnp->property_map); g_hash_table_unref(upnp->filter_map); - g_hash_table_unref(upnp->server_udn_map); - g_hash_table_unref(upnp->server_uc_map); + g_hash_table_unref(upnp->device_udn_map); + g_hash_table_unref(upnp->device_uc_map); g_free(upnp); } } -GVariant *dls_upnp_get_server_ids(dls_upnp_t *upnp) +GVariant *dls_upnp_get_device_ids(dls_upnp_t *upnp) { GVariantBuilder vb; GHashTableIter iter; @@ -420,7 +480,7 @@ GVariant *dls_upnp_get_server_ids(dls_upnp_t *upnp) g_variant_builder_init(&vb, G_VARIANT_TYPE("ao")); - g_hash_table_iter_init(&iter, upnp->server_udn_map); + g_hash_table_iter_init(&iter, upnp->device_udn_map); while (g_hash_table_iter_next(&iter, NULL, &value)) { device = value; DLEYNA_LOG_DEBUG("Have device %s", device->path); @@ -434,9 +494,9 @@ GVariant *dls_upnp_get_server_ids(dls_upnp_t *upnp) return retval; } -GHashTable *dls_upnp_get_server_udn_map(dls_upnp_t *upnp) +GHashTable *dls_upnp_get_device_udn_map(dls_upnp_t *upnp) { - return upnp->server_udn_map; + return upnp->device_udn_map; } void dls_upnp_get_children(dls_upnp_t *upnp, dls_client_t *client, @@ -1088,6 +1148,21 @@ void dls_upnp_get_icon(dls_upnp_t *upnp, dls_client_t *client, DLEYNA_LOG_DEBUG("Exit"); } +void dls_upnp_wake(dls_upnp_t *upnp, dls_client_t *client, + dls_task_t *task, + dls_upnp_task_complete_t cb) +{ + dls_async_task_t *cb_data = (dls_async_task_t *)task; + + DLEYNA_LOG_DEBUG("Enter"); + + cb_data->cb = cb; + + dls_device_wake(client, task); + + DLEYNA_LOG_DEBUG("Exit"); +} + void dls_upnp_unsubscribe(dls_upnp_t *upnp) { GHashTableIter iter; @@ -1096,7 +1171,7 @@ void dls_upnp_unsubscribe(dls_upnp_t *upnp) DLEYNA_LOG_DEBUG("Enter"); - g_hash_table_iter_init(&iter, upnp->server_udn_map); + g_hash_table_iter_init(&iter, upnp->device_udn_map); while (g_hash_table_iter_next(&iter, NULL, &value)) { device = value; dls_device_unsubscribe(device); @@ -1131,11 +1206,11 @@ gboolean dls_upnp_device_context_exist(dls_device_t *device, goto on_exit; /* Check if the device still exist */ - result = g_hash_table_find(upnp->server_udn_map, prv_device_find, + result = g_hash_table_find(upnp->device_udn_map, prv_device_find, device); if (result == NULL) - if (g_hash_table_find(upnp->server_uc_map, prv_device_uc_find, + if (g_hash_table_find(upnp->device_uc_map, prv_device_uc_find, device) == NULL) goto on_exit; diff --git a/libdleyna/server/upnp.h b/libdleyna/server/upnp.h index 08441c6..b2d9ba1 100644 --- a/libdleyna/server/upnp.h +++ b/libdleyna/server/upnp.h @@ -39,9 +39,9 @@ dls_upnp_t *dls_upnp_new(dleyna_connector_id_t connection, void dls_upnp_delete(dls_upnp_t *upnp); -GVariant *dls_upnp_get_server_ids(dls_upnp_t *upnp); +GVariant *dls_upnp_get_device_ids(dls_upnp_t *upnp); -GHashTable *dls_upnp_get_server_udn_map(dls_upnp_t *upnp); +GHashTable *dls_upnp_get_device_udn_map(dls_upnp_t *upnp); void dls_upnp_get_children(dls_upnp_t *upnp, dls_client_t *client, dls_task_t *task, @@ -109,6 +109,10 @@ void dls_upnp_get_icon(dls_upnp_t *upnp, dls_client_t *client, dls_task_t *task, dls_upnp_task_complete_t cb); +void dls_upnp_wake(dls_upnp_t *upnp, dls_client_t *client, + dls_task_t *task, + dls_upnp_task_complete_t cb); + void dls_upnp_unsubscribe(dls_upnp_t *upnp); gboolean dls_upnp_device_context_exist(dls_device_t *device, diff --git a/libdleyna/server/xml-util.c b/libdleyna/server/xml-util.c new file mode 100644 index 0000000..f6ddf6a --- /dev/null +++ b/libdleyna/server/xml-util.c @@ -0,0 +1,133 @@ +/* + * dLeyna + * + * Copyright (C) 2012-2013 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU Lesser General Public License, + * version 2.1, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * Christophe Guiraud <christophe.guiraud@intel.com> + * + */ + +#include <string.h> +#include <stdlib.h> + +#include "xml-util.h" + +static xmlNode *prv_get_child_node(xmlNode *node, va_list args) +{ + const gchar *name; + + name = va_arg(args, const gchar *); + while (name != NULL) { + node = node->children; + while (node != NULL) { + if (node->name != NULL && + !strcmp(name, (char *)node->name)) + break; + + node = node->next; + } + + if (node == NULL) + break; + + name = va_arg(args, const gchar *); + } + + return node; +} + +static GList *prv_get_children_list(xmlNode *node, const gchar *name) +{ + GList *child_list = NULL; + + node = node->children; + while (node != NULL) { + if (node->name != NULL && + !strcmp(name, (char *)node->name)) + child_list = g_list_prepend(child_list, node); + + node = node->next; + } + + return child_list; +} + +GList *xml_util_get_child_string_list_content_by_name(xmlNode *node, ...) +{ + xmlChar *content; + va_list args; + GList *child_list = NULL; + GList *next; + GList *str_list = NULL; + xmlNode *child_list_node; + xmlNode *child_node; + + va_start(args, node); + + child_node = prv_get_child_node(node, args); + + va_end(args); + + if (child_node != NULL) { + child_list = prv_get_children_list(child_node->parent, + (const gchar *)child_node->name); + next = child_list; + while (next) { + child_list_node = (xmlNode *)next->data; + + content = xmlNodeGetContent(child_list_node); + + if (content != NULL) { + str_list = g_list_prepend(str_list, + g_strdup((gchar *)content)); + + xmlFree(content); + } + + next = g_list_next(next); + } + + g_list_free(child_list); + } + + return str_list; +} + +gchar *xml_util_get_child_string_content_by_name(xmlNode *node, ...) +{ + xmlChar *content; + va_list args; + gchar *str = NULL; + xmlNode *child_node; + + va_start(args, node); + + child_node = prv_get_child_node(node, args); + + va_end(args); + + if (child_node != NULL) { + content = xmlNodeGetContent(child_node); + + if (content != NULL) { + str = g_strdup((gchar *)content); + + xmlFree(content); + } + } + + return str; +} diff --git a/libdleyna/server/xml-util.h b/libdleyna/server/xml-util.h new file mode 100644 index 0000000..d5c72f4 --- /dev/null +++ b/libdleyna/server/xml-util.h @@ -0,0 +1,35 @@ +/* + * dLeyna + * + * Copyright (C) 2012-2013 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU Lesser General Public License, + * version 2.1, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * Christophe Guiraud <christophe.guiraud@intel.com> + * + */ + + +#ifndef DLS_XML_UTIL_H__ +#define DLS_XML_UTIL_H__ + +#include <glib.h> +#include <stdarg.h> +#include <libxml/tree.h> + +GList *xml_util_get_child_string_list_content_by_name(xmlNode *node, ...); + +gchar *xml_util_get_child_string_content_by_name(xmlNode *node, ...); + +#endif /* DLS_XML_UTIL_H__ */ diff --git a/test/dbus/mediaconsole.py b/test/dbus/mediaconsole.py index d54bb84..887c1f1 100644 --- a/test/dbus/mediaconsole.py +++ b/test/dbus/mediaconsole.py @@ -191,6 +191,9 @@ class Device(Container): bytes, mime = self._deviceIF.GetIcon(mime_type, resolution) print "Icon mime type: " + mime + def wake(self): + return self._deviceIF.Wake() + class UPNP(object): def __init__(self): |