diff options
-rw-r--r-- | libdleyna/server/device.c | 63 | ||||
-rw-r--r-- | libdleyna/server/device.h | 4 | ||||
-rw-r--r-- | libdleyna/server/server.c | 14 | ||||
-rw-r--r-- | libdleyna/server/server.h | 2 | ||||
-rw-r--r-- | libdleyna/server/task.c | 24 | ||||
-rw-r--r-- | libdleyna/server/upnp.c | 107 | ||||
-rw-r--r-- | libdleyna/server/upnp.h | 2 |
7 files changed, 182 insertions, 34 deletions
diff --git a/libdleyna/server/device.c b/libdleyna/server/device.c index cc842ee..79f2fc1 100644 --- a/libdleyna/server/device.c +++ b/libdleyna/server/device.c @@ -21,6 +21,7 @@ */ #include <string.h> +#include <stdint.h> #include <libgupnp/gupnp-error.h> #include <libgupnp-dlna/gupnp-dlna-profile.h> #include <libgupnp-dlna/gupnp-dlna-profile-guesser.h> @@ -228,10 +229,8 @@ static void prv_context_unsubscribe(dls_device_context_t *ctx) } } -static void prv_context_delete(gpointer context) +void dls_device_delete_context(dls_device_context_t *ctx) { - dls_device_context_t *ctx = context; - if (ctx) { prv_context_unsubscribe(ctx); @@ -254,6 +253,7 @@ static void prv_context_delete(gpointer context) } } + static GUPnPServiceInfo *prv_lookup_em_service(GUPnPDeviceInfo *device_info) { GList *child_devices; @@ -346,6 +346,7 @@ void dls_device_delete(void *device) dev->connection, dev->id); g_ptr_array_unref(dev->contexts); + dls_device_delete_context(dev->sleeping_context); g_free(dev->path); g_variant_unref(dev->search_caps); g_variant_unref(dev->sort_caps); @@ -577,43 +578,49 @@ static dls_network_if_info_t *prv_get_network_if_info(xmlNode *device_if_node) 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); + 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); + 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); + device_if_node, + "DeviceUUID", + NULL); info->mac_address = xml_util_get_child_string_content_by_name( - device_if_node, - "NetworkInterface", - "MacAddress", NULL); + device_if_node, + "NetworkInterface", + "MacAddress", + NULL); info->network_if_mode = xml_util_get_child_string_content_by_name( - device_if_node, - "NetworkInterface", - "NetworkInterfaceMode" - , NULL); + device_if_node, + "NetworkInterface", + "NetworkInterfaceMode", + NULL); info->wake_on_pattern = xml_util_get_child_string_content_by_name( - device_if_node, - "NetworkInterface", - "WakeOnPattern", NULL); + device_if_node, + "NetworkInterface", + "WakeOnPattern", + NULL); info->wake_transport = xml_util_get_child_string_content_by_name( device_if_node, "NetworkInterface", - "WakeSupportedTransport", NULL); + "WakeSupportedTransport", + NULL); if ((info->device_uuid == NULL || strlen(info->device_uuid) > 70) || (info->mac_address == NULL || strlen(info->mac_address) != 17) || @@ -1590,7 +1597,8 @@ dls_device_t *dls_device_new( dev = g_new0(dls_device_t, 1); dev->connection = connection; - dev->contexts = g_ptr_array_new_with_free_func(prv_context_delete); + dev->contexts = g_ptr_array_new_with_free_func((GDestroyNotify) + dls_device_delete_context); dev->path = new_path; context = dls_device_append_new_context(dev, ip_address, @@ -3045,7 +3053,10 @@ void dls_device_get_prop(dls_client_t *client, DLEYNA_LOG_DEBUG("Enter"); - context = dls_device_get_context(task->target.device, client); + if (task->target.device->contexts->len != 0) + context = dls_device_get_context(task->target.device, client); + else + context = task->target.device->sleeping_context; if (!strcmp(task_data->interface_name, DLEYNA_SERVER_INTERFACE_MEDIA_DEVICE)) { diff --git a/libdleyna/server/device.h b/libdleyna/server/device.h index 891351c..24b3cc4 100644 --- a/libdleyna/server/device.h +++ b/libdleyna/server/device.h @@ -72,6 +72,7 @@ struct dls_device_t_ { guint id; gchar *path; GPtrArray *contexts; + dls_device_context_t *sleeping_context; guint timeout_id; GHashTable *uploads; GHashTable *upload_jobs; @@ -92,6 +93,7 @@ dls_device_context_t *dls_device_append_new_context(dls_device_t *device, const gchar *ip_address, GUPnPDeviceProxy *proxy, GUPnPDeviceInfo *device_info); + void dls_device_delete(void *device); void dls_device_unsubscribe(void *device); @@ -119,6 +121,8 @@ dls_device_t *dls_device_from_path(const gchar *path, GHashTable *device_list); dls_device_context_t *dls_device_get_context(const dls_device_t *device, dls_client_t *client); +void dls_device_delete_context(dls_device_context_t *context); + void dls_device_get_children(dls_client_t *client, dls_task_t *task, const gchar *upnp_filter, const gchar *sort_by); diff --git a/libdleyna/server/server.c b/libdleyna/server/server.c index 5367252..1673ccd 100644 --- a/libdleyna/server/server.c +++ b/libdleyna/server/server.c @@ -945,6 +945,12 @@ gboolean dls_server_get_object_info(const gchar *object_path, dls_upnp_get_device_udn_map(g_context.upnp)); if (*device == NULL) { + *device = dls_device_from_path(*root_path, + dls_upnp_get_sleeping_device_udn_map( + g_context.upnp)); + } + + if (*device == NULL) { DLEYNA_LOG_WARNING("Cannot locate device for %s", *root_path); *error = g_error_new(DLEYNA_SERVER_ERROR, @@ -965,6 +971,14 @@ on_error: return FALSE; } +gboolean dls_server_is_device_sleeping(dls_device_t *dev) +{ + if (dev->sleeping_context != NULL) + return TRUE; + else + return FALSE; +} + static const gchar *prv_get_device_id(const gchar *object, GError **error) { dls_device_t *device; diff --git a/libdleyna/server/server.h b/libdleyna/server/server.h index 01d9356..36261de 100644 --- a/libdleyna/server/server.h +++ b/libdleyna/server/server.h @@ -40,6 +40,8 @@ gboolean dls_server_get_object_info(const gchar *object_path, dls_upnp_t *dls_server_get_upnp(void); +gboolean dls_server_is_device_sleeping(dls_device_t *dev); + dleyna_task_processor_t *dls_server_get_task_processor(void); const dleyna_connector_t *dls_server_get_connector(void); diff --git a/libdleyna/server/task.c b/libdleyna/server/task.c index 312efc0..ec63d8e 100644 --- a/libdleyna/server/task.c +++ b/libdleyna/server/task.c @@ -222,6 +222,24 @@ static gboolean prv_set_task_target_info(dls_task_t *task, const gchar *path, &task->target.device, error); } +static gboolean prv_is_task_allowed(dls_task_t *task, GError **error) +{ + if (dls_server_is_device_sleeping(task->target.device)) { + if (task->type != DLS_TASK_WAKE && + task->type != DLS_TASK_GET_PROP) + goto on_error; + } + + return TRUE; + +on_error: + *error = g_error_new(DLEYNA_SERVER_ERROR, + DLEYNA_ERROR_OPERATION_FAILED, + "Target device is sleeping"); + + return FALSE; +} + static dls_task_t *prv_m2spec_task_new(dls_task_type_t type, dleyna_connector_msg_id_t invocation, const gchar *path, @@ -238,14 +256,16 @@ static dls_task_t *prv_m2spec_task_new(dls_task_type_t type, task = (dls_task_t *)g_new0(dls_async_task_t, 1); } - if (!prv_set_task_target_info(task, path, error)) { + task->type = type; + + if (!prv_set_task_target_info(task, path, error) || + !prv_is_task_allowed(task, error)) { prv_delete(task); task = NULL; goto finished; } - task->type = type; task->invocation = invocation; task->result_format = result_format; diff --git a/libdleyna/server/upnp.c b/libdleyna/server/upnp.c index 7301e61..3074645 100644 --- a/libdleyna/server/upnp.c +++ b/libdleyna/server/upnp.c @@ -50,6 +50,7 @@ struct dls_upnp_t_ { GUPnPContextManager *context_manager; void *user_data; GHashTable *device_udn_map; + GHashTable *sleeping_device_udn_map; GHashTable *device_uc_map; guint counter; }; @@ -205,6 +206,9 @@ static void prv_device_available_cb(GUPnPControlPoint *cp, GUPnPDeviceInfo *device_proxy = (GUPnPDeviceInfo *)proxy; GUPnPDeviceInfo *device_info = NULL; const gchar *device_type; + gboolean subscribe = FALSE; + gpointer key; + gpointer val; udn = gupnp_device_info_get_udn(device_proxy); @@ -231,6 +235,33 @@ static void prv_device_available_cb(GUPnPControlPoint *cp, device = g_hash_table_lookup(upnp->device_udn_map, udn); if (!device) { + device = g_hash_table_lookup(upnp->sleeping_device_udn_map, + udn); + + if (device != NULL) { + if (g_hash_table_lookup_extended( + upnp->sleeping_device_udn_map, + udn, + &key, + &val)) { + g_hash_table_steal( + upnp->sleeping_device_udn_map, + udn); + + g_free(key); + } + + g_hash_table_insert(upnp->device_udn_map, g_strdup(udn), + device); + + dls_device_delete_context(device->sleeping_context); + device->sleeping_context = NULL; + device->sleeping = FALSE; + subscribe = TRUE; + } + } + + if (!device) { priv_t = g_hash_table_lookup(upnp->device_uc_map, udn); if (priv_t) @@ -270,6 +301,8 @@ static void prv_device_available_cb(GUPnPControlPoint *cp, ip_address, proxy, device_info); + if (subscribe) + dls_device_subscribe_to_service_changes(device); } DLEYNA_LOG_DEBUG_NL(); @@ -305,6 +338,9 @@ static void prv_device_unavailable_cb(GUPnPControlPoint *cp, gboolean under_construction = FALSE; prv_device_new_ct_t *priv_t; const dleyna_task_queue_key_t *queue_id; + dls_device_context_t *lost_context; + gpointer key; + gpointer val; DLEYNA_LOG_DEBUG("Enter"); @@ -349,13 +385,51 @@ static void prv_device_unavailable_cb(GUPnPControlPoint *cp, construction_ctx = !strcmp(context->ip_address, priv_t->ip_address); - (void) g_ptr_array_remove_index(device->contexts, i); + g_ptr_array_set_free_func(device->contexts, NULL); + + lost_context = g_ptr_array_remove_index(device->contexts, i); + + g_ptr_array_set_free_func(device->contexts, + (GDestroyNotify)dls_device_delete_context); if (device->contexts->len == 0) { if (!under_construction) { - DLEYNA_LOG_DEBUG("Last Context lost. Delete device"); - upnp->lost_server(device->path, upnp->user_data); - g_hash_table_remove(upnp->device_udn_map, udn); + DLEYNA_LOG_DEBUG("Last Context lost."); + + if (!device->sleeping) { + DLEYNA_LOG_DEBUG("Delete device."); + + upnp->lost_server(device->path, + upnp->user_data); + + g_hash_table_remove(upnp->device_udn_map, udn); + } else { + DLEYNA_LOG_DEBUG("Persist sleeping device."); + + dleyna_task_processor_remove_queues_for_sink( + dls_server_get_task_processor(), + device->path); + + g_hash_table_insert( + upnp->sleeping_device_udn_map, + g_strdup(udn), + device); + + if (g_hash_table_lookup_extended( + upnp->device_udn_map, + udn, + &key, + &val)) { + g_hash_table_steal(upnp->device_udn_map, + udn); + + g_free(key); + } + + device->sleeping_context = lost_context; + + lost_context = NULL; + } } else { DLEYNA_LOG_WARNING( "Device under construction. Cancelling"); @@ -394,6 +468,9 @@ static void prv_device_unavailable_cb(GUPnPControlPoint *cp, device); } + if (lost_context != NULL) + dls_device_delete_context(lost_context); + on_error: DLEYNA_LOG_DEBUG("Exit"); @@ -439,8 +516,13 @@ dls_upnp_t *dls_upnp_new(dleyna_connector_id_t connection, upnp->lost_server = lost_server; upnp->device_udn_map = g_hash_table_new_full(g_str_hash, g_str_equal, - g_free, - dls_device_delete); + g_free, + dls_device_delete); + + upnp->sleeping_device_udn_map = g_hash_table_new_full(g_str_hash, + g_str_equal, + g_free, + dls_device_delete); upnp->device_uc_map = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); @@ -463,6 +545,7 @@ void dls_upnp_delete(dls_upnp_t *upnp) g_hash_table_unref(upnp->property_map); g_hash_table_unref(upnp->filter_map); g_hash_table_unref(upnp->device_udn_map); + g_hash_table_unref(upnp->sleeping_device_udn_map); g_hash_table_unref(upnp->device_uc_map); g_free(upnp); } @@ -487,6 +570,13 @@ GVariant *dls_upnp_get_device_ids(dls_upnp_t *upnp) g_variant_builder_add(&vb, "o", device->path); } + g_hash_table_iter_init(&iter, upnp->sleeping_device_udn_map); + while (g_hash_table_iter_next(&iter, NULL, &value)) { + device = value; + DLEYNA_LOG_DEBUG("Have sleeping device %s", device->path); + g_variant_builder_add(&vb, "o", device->path); + } + retval = g_variant_ref_sink(g_variant_builder_end(&vb)); DLEYNA_LOG_DEBUG("Exit"); @@ -499,6 +589,11 @@ GHashTable *dls_upnp_get_device_udn_map(dls_upnp_t *upnp) return upnp->device_udn_map; } +GHashTable *dls_upnp_get_sleeping_device_udn_map(dls_upnp_t *upnp) +{ + return upnp->sleeping_device_udn_map; +} + void dls_upnp_get_children(dls_upnp_t *upnp, dls_client_t *client, dls_task_t *task, dls_upnp_task_complete_t cb) diff --git a/libdleyna/server/upnp.h b/libdleyna/server/upnp.h index b2d9ba1..fc1b3a3 100644 --- a/libdleyna/server/upnp.h +++ b/libdleyna/server/upnp.h @@ -43,6 +43,8 @@ GVariant *dls_upnp_get_device_ids(dls_upnp_t *upnp); GHashTable *dls_upnp_get_device_udn_map(dls_upnp_t *upnp); +GHashTable *dls_upnp_get_sleeping_device_udn_map(dls_upnp_t *upnp); + void dls_upnp_get_children(dls_upnp_t *upnp, dls_client_t *client, dls_task_t *task, dls_upnp_task_complete_t cb); |