summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libdleyna/server/device.c63
-rw-r--r--libdleyna/server/device.h4
-rw-r--r--libdleyna/server/server.c14
-rw-r--r--libdleyna/server/server.h2
-rw-r--r--libdleyna/server/task.c24
-rw-r--r--libdleyna/server/upnp.c107
-rw-r--r--libdleyna/server/upnp.h2
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);