summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristophe Guiraud <christophe.guiraud@intel.com>2013-08-06 10:52:06 +0200
committerrmerlino <regis.merlino@intel.com>2013-12-12 14:51:39 +0100
commite1016524888d652aeb8470cdc54db35619cd6d6d (patch)
tree87f16ca5f9d44de036beaa3b559cc6074c84c1ab
parente0a29b4f4596f04831f0aa6b863b0c3d53c598ee (diff)
downloaddleyna-server-e1016524888d652aeb8470cdc54db35619cd6d6d.tar.gz
[Device] Retrieve sleeping state via GetInterfaceInfo action
Some devices may continue to send SSDP messages even if they are asleep. Thus we cannot assume that a device is awake just because we can discover it. If a device is dicovered we need to retrieve it's sleeping state via the UPnP GetInterfaceInfo action. Signed-off-by: Christophe Guiraud <christophe.guiraud@intel.com>
-rw-r--r--libdleyna/server/async.h1
-rw-r--r--libdleyna/server/device.c296
-rw-r--r--libdleyna/server/props.c15
-rw-r--r--libdleyna/server/props.h1
-rw-r--r--libdleyna/server/server.c2
5 files changed, 283 insertions, 32 deletions
diff --git a/libdleyna/server/async.h b/libdleyna/server/async.h
index c5e1579..2408b4b 100644
--- a/libdleyna/server/async.h
+++ b/libdleyna/server/async.h
@@ -62,6 +62,7 @@ struct dls_async_get_all_t_ {
const gchar *protocol_info;
gboolean need_child_count;
gboolean device_object;
+ GUPnPServiceProxy *proxy;
};
typedef struct dls_async_upload_t_ dls_async_upload_t;
diff --git a/libdleyna/server/device.c b/libdleyna/server/device.c
index 79f2fc1..c4f1f62 100644
--- a/libdleyna/server/device.c
+++ b/libdleyna/server/device.c
@@ -157,6 +157,10 @@ static GUPnPServiceProxyAction *prv_browse_objects_begin_action_cb(
GUPnPServiceProxy *proxy,
gboolean *failed);
+static void prv_get_sleeping_for_props(GUPnPServiceProxy *proxy,
+ const dls_device_t *device,
+ dls_async_task_t *cb_data);
+
static void prv_free_network_if_info(dls_network_if_info_t *info);
static void prv_object_builder_delete(void *dob)
@@ -706,9 +710,17 @@ static gboolean prv_lookup_device_ctx_network_if_info(dls_device_context_t *ctx,
next = info->ip_addresses;
while (next != NULL) {
ip_address = (gchar *)next->data;
+ DLEYNA_LOG_DEBUG("Network Interface Info: IP address = %s",
+ ip_address);
+
if (!strcmp(ctx->ip_address, ip_address)) {
udn = gupnp_device_info_get_udn((GUPnPDeviceInfo *)
ctx->device_proxy);
+
+ DLEYNA_LOG_DEBUG("Device Context: UUID = %s", udn);
+ DLEYNA_LOG_DEBUG("Network Interface Info: UUID = %s",
+ info->device_uuid);
+
if (!strcmp(info->device_uuid, udn)) {
found = TRUE;
if (!strcmp(info->network_if_mode, "IP-up"))
@@ -718,8 +730,11 @@ static gboolean prv_lookup_device_ctx_network_if_info(dls_device_context_t *ctx,
}
}
- if (found)
+ if (found) {
+ DLEYNA_LOG_DEBUG("Network Interface Info: mode = %s",
+ info->network_if_mode);
break;
+ }
next = g_list_next(next);
}
@@ -747,6 +762,8 @@ static gboolean prv_get_device_sleeping_state(dls_device_t *device,
info = (dls_network_if_info_t *)next->data;
for (i = 0; i < device->contexts->len; ++i) {
ctx = g_ptr_array_index(device->contexts, i);
+ DLEYNA_LOG_DEBUG("Device Context[%u]: IP address = %s",
+ i, ctx->ip_address);
found = prv_lookup_device_ctx_network_if_info(ctx,
info,
sleeping);
@@ -2233,6 +2250,7 @@ static void prv_get_system_update_id_for_props(GUPnPServiceProxy *proxy,
(gpointer *)&cb_data->proxy);
cb_data->proxy = proxy;
+
g_object_add_weak_pointer((G_OBJECT(proxy)),
(gpointer *)&cb_data->proxy);
@@ -2247,6 +2265,136 @@ on_complete:
DLEYNA_LOG_DEBUG("Exit");
}
+static gboolean prv_ems_subscribed(const dls_device_t *device)
+{
+ dls_device_context_t *context;
+ unsigned int i;
+ gboolean subscribed = FALSE;
+
+ for (i = 0; i < device->contexts->len; ++i) {
+ context = g_ptr_array_index(device->contexts, i);
+ if (context->ems.subscribed) {
+ subscribed = TRUE;
+ break;
+ }
+ }
+
+ return subscribed;
+}
+
+static void prv_sleeping_for_props_cb(GUPnPServiceProxy *proxy,
+ GUPnPServiceProxyAction *action,
+ gpointer user_data)
+{
+ GError *error = NULL;
+ const gchar *message;
+ gchar *info = NULL;
+ gboolean end;
+ dls_async_task_t *cb_data = user_data;
+ dls_async_get_all_t *cb_task_data;
+ gboolean sleeping;
+
+ DLEYNA_LOG_DEBUG("Enter");
+
+ end = gupnp_service_proxy_end_action(proxy, action, &error,
+ "NetworkInterfaceInfo",
+ G_TYPE_STRING,
+ &info, NULL);
+
+ if (!end || (info == NULL)) {
+ message = (error != NULL) ? error->message : "Invalid result";
+ DLEYNA_LOG_WARNING("NetworkInterfaceInfo retrieval failed: %s",
+ message);
+
+ cb_data->error = g_error_new(DLEYNA_SERVER_ERROR,
+ DLEYNA_ERROR_OPERATION_FAILED,
+ "GetInterfaceInfo failed: %s",
+ message);
+ goto on_complete;
+ }
+
+ if (prv_get_device_sleeping_state(cb_data->task.target.device,
+ info,
+ &sleeping)) {
+ cb_task_data = &cb_data->ut.get_all;
+ g_variant_builder_add(cb_task_data->vb, "{sv}",
+ DLS_INTERFACE_PROP_SLEEPING,
+ g_variant_new_boolean(sleeping));
+
+ cb_data->task.result = g_variant_ref_sink(g_variant_builder_end(
+ cb_task_data->vb));
+ }
+
+ g_free(info);
+
+on_complete:
+
+ (void) g_idle_add(dls_async_task_complete, cb_data);
+ g_cancellable_disconnect(cb_data->cancellable, cb_data->cancel_id);
+
+ if (error)
+ g_error_free(error);
+
+ DLEYNA_LOG_DEBUG("Exit");
+}
+
+static void prv_get_sleeping_for_props(GUPnPServiceProxy *proxy,
+ const dls_device_t *device,
+ dls_async_task_t *cb_data)
+{
+ dls_async_get_all_t *cb_task_data;
+ gboolean sleeping;
+
+ DLEYNA_LOG_DEBUG("Enter");
+
+ cb_task_data = &cb_data->ut.get_all;
+
+ if (proxy == NULL)
+ goto on_complete;
+
+ if (prv_ems_subscribed(device)) {
+ sleeping = device->sleeping;
+
+ g_variant_builder_add(cb_task_data->vb, "{sv}",
+ DLS_INTERFACE_PROP_SLEEPING,
+ g_variant_new_boolean(sleeping));
+
+ goto on_complete;
+ }
+
+ cb_data->action = gupnp_service_proxy_begin_action(
+ proxy, "GetInterfaceInfo",
+ prv_sleeping_for_props_cb,
+ cb_data,
+ NULL);
+
+ if (cb_data->proxy != NULL)
+ g_object_remove_weak_pointer((G_OBJECT(cb_data->proxy)),
+ (gpointer *)&cb_data->proxy);
+
+ cb_data->proxy = proxy;
+
+ g_object_add_weak_pointer((G_OBJECT(proxy)),
+ (gpointer *)&cb_data->proxy);
+
+ if (!cb_data->cancel_id)
+ cb_data->cancel_id = g_cancellable_connect(
+ cb_data->cancellable,
+ G_CALLBACK(dls_async_task_cancelled_cb),
+ cb_data, NULL);
+
+ return;
+
+on_complete:
+
+ cb_data->task.result = g_variant_ref_sink(g_variant_builder_end(
+ cb_task_data->vb));
+
+ (void) g_idle_add(dls_async_task_complete, cb_data);
+
+ DLEYNA_LOG_DEBUG("Exit");
+}
+
static int prv_get_media_server_version(const dls_device_t *device)
{
dls_device_context_t *context;
@@ -2364,6 +2512,8 @@ static void prv_service_reset_for_props_cb(GUPnPServiceProxy *proxy,
DLEYNA_LOG_DEBUG("Enter");
+ cb_task_data = &cb_data->ut.get_all;
+
end = gupnp_service_proxy_end_action(proxy, action, &error,
"ResetToken", G_TYPE_STRING,
&token, NULL);
@@ -2380,22 +2530,28 @@ static void prv_service_reset_for_props_cb(GUPnPServiceProxy *proxy,
goto on_complete;
}
- cb_task_data = &cb_data->ut.get_all;
g_variant_builder_add(cb_task_data->vb, "{sv}",
DLS_INTERFACE_PROP_SV_SERVICE_RESET_TOKEN,
g_variant_new_string(token));
- cb_data->task.result = g_variant_ref_sink(g_variant_builder_end(
- cb_task_data->vb));
-
DLEYNA_LOG_DEBUG("Service Reset %s", token);
g_free(token);
on_complete:
- (void) g_idle_add(dls_async_task_complete, cb_data);
- g_cancellable_disconnect(cb_data->cancellable, cb_data->cancel_id);
+ if ((!cb_data->error) && (cb_task_data->proxy))
+ prv_get_sleeping_for_props(cb_task_data->proxy,
+ cb_data->task.target.device,
+ cb_data);
+ else {
+ cb_data->task.result = g_variant_ref_sink(g_variant_builder_end(
+ cb_task_data->vb));
+
+ (void) g_idle_add(dls_async_task_complete, cb_data);
+ g_cancellable_disconnect(cb_data->cancellable,
+ cb_data->cancel_id);
+ }
if (error)
g_error_free(error);
@@ -2414,10 +2570,10 @@ static void prv_get_sr_token_for_props(GUPnPServiceProxy *proxy,
if (prv_get_media_server_version(device) < 3) {
cb_task_data = &cb_data->ut.get_all;
- cb_data->task.result = g_variant_ref_sink(g_variant_builder_end(
- cb_task_data->vb));
+ prv_get_sleeping_for_props(cb_task_data->proxy,
+ device, cb_data);
- goto on_complete; /* No error here, just skip the property */
+ goto on_exit; /* No error here, just skip the property */
}
cb_data->action = gupnp_service_proxy_begin_action(
@@ -2440,13 +2596,107 @@ static void prv_get_sr_token_for_props(GUPnPServiceProxy *proxy,
G_CALLBACK(dls_async_task_cancelled_cb),
cb_data, NULL);
+on_exit:
+
DLEYNA_LOG_DEBUG("Exit");
return;
+}
+
+static void prv_sleeping_for_prop_cb(GUPnPServiceProxy *proxy,
+ GUPnPServiceProxyAction *action,
+ gpointer user_data)
+{
+ GError *error = NULL;
+ const gchar *message;
+ gchar *info = NULL;
+ gboolean end;
+ dls_async_task_t *cb_data = user_data;
+ gboolean sleeping;
+
+ DLEYNA_LOG_DEBUG("Enter");
+
+ end = gupnp_service_proxy_end_action(proxy, action, &error,
+ "NetworkInterfaceInfo",
+ G_TYPE_STRING,
+ &info, NULL);
+
+ if (!end || (info == NULL)) {
+ message = (error != NULL) ? error->message : "Invalid result";
+ DLEYNA_LOG_WARNING("NetworkInterfaceInfo retrieval failed: %s",
+ message);
+
+ cb_data->error = g_error_new(DLEYNA_SERVER_ERROR,
+ DLEYNA_ERROR_OPERATION_FAILED,
+ "GetNetworkInterfaceInfo failed: %s",
+ message);
+
+ goto on_complete;
+ }
+
+ if (prv_get_device_sleeping_state(cb_data->task.target.device,
+ info,
+ &sleeping)) {
+ cb_data->task.result = g_variant_ref_sink(
+ g_variant_new_boolean(sleeping));
+ }
+
+ g_free(info);
on_complete:
(void) g_idle_add(dls_async_task_complete, cb_data);
+ g_cancellable_disconnect(cb_data->cancellable, cb_data->cancel_id);
+
+ if (error)
+ g_error_free(error);
+
+ DLEYNA_LOG_DEBUG("Exit");
+}
+
+static void prv_get_sleeping_for_prop(GUPnPServiceProxy *proxy,
+ const dls_device_t *device,
+ dls_async_task_t *cb_data)
+{
+ gboolean sleeping;
+
+ DLEYNA_LOG_DEBUG("Enter");
+
+ if (proxy == NULL) {
+ cb_data->error = g_error_new(DLEYNA_SERVER_ERROR,
+ DLEYNA_ERROR_UNKNOWN_PROPERTY,
+ "Unknown property");
+
+ (void) g_idle_add(dls_async_task_complete, cb_data);
+
+ goto on_complete;
+ } else if ((device->contexts->len == 0) || prv_ems_subscribed(device)) {
+ sleeping = device->sleeping;
+
+ cb_data->task.result = g_variant_ref_sink(
+ g_variant_new_boolean(sleeping));
+
+ (void) g_idle_add(dls_async_task_complete, cb_data);
+
+ goto on_complete;
+ }
+
+ cb_data->action = gupnp_service_proxy_begin_action(
+ proxy, "GetInterfaceInfo",
+ prv_sleeping_for_prop_cb,
+ cb_data,
+ NULL);
+
+ cb_data->proxy = proxy;
+
+ g_object_add_weak_pointer((G_OBJECT(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);
+on_complete:
DLEYNA_LOG_DEBUG("Exit");
}
@@ -2538,7 +2788,6 @@ 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);
@@ -2646,6 +2895,7 @@ void dls_device_get_all_props(dls_client_t *client,
cb_task_data->vb = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
cb_task_data->device_object = root_object;
+ cb_task_data->proxy = context->ems.proxy;
if (!strcmp(task_data->interface_name,
DLEYNA_SERVER_INTERFACE_MEDIA_DEVICE)) {
@@ -3075,19 +3325,25 @@ void dls_device_get_prop(dls_client_t *client,
context->cds.proxy,
task->target.device,
cb_data);
+ } else if (!strcmp(
+ task_data->prop_name,
+ DLS_INTERFACE_PROP_SLEEPING)) {
+ prv_get_sleeping_for_prop(
+ context->ems.proxy,
+ task->target.device,
+ cb_data);
} else {
cb_data->task.result =
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)
cb_data->error = g_error_new(
- DLEYNA_SERVER_ERROR,
+ DLEYNA_SERVER_ERROR,
DLEYNA_ERROR_UNKNOWN_PROPERTY,
"Unknown property");
@@ -3125,13 +3381,20 @@ void dls_device_get_prop(dls_client_t *client,
task->target.device,
cb_data);
complete = TRUE;
+ } else if (!strcmp(
+ task_data->prop_name,
+ DLS_INTERFACE_PROP_SLEEPING)) {
+ prv_get_sleeping_for_prop(
+ context->ems.proxy,
+ task->target.device,
+ cb_data);
+ complete = TRUE;
} else {
cb_data->task.result =
dls_props_get_device_prop(
(GUPnPDeviceInfo *)
context->device_proxy,
context->device_info,
- context->ems.proxy,
task->target.device,
task_data->prop_name);
@@ -3841,6 +4104,7 @@ void dls_device_get_resource(dls_client_t *client,
cb_task_data->vb = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
cb_task_data->prop_func = G_CALLBACK(prv_get_resource);
cb_task_data->device_object = FALSE;
+ cb_task_data->proxy = context->ems.proxy;
cb_data->proxy = context->cds.proxy;
@@ -5677,8 +5941,10 @@ void dls_device_wake(dls_client_t *client, dls_task_t *task)
context = dls_device_get_context(device, client);
- if (!device->sleeping)
+ if (!device->sleeping) {
+ DLEYNA_LOG_DEBUG("Device is not sleeping");
goto on_complete;
+ }
if ((context->ems.proxy == NULL) ||
(context->network_if_info == NULL)) {
diff --git a/libdleyna/server/props.c b/libdleyna/server/props.c
index 4196e68..fc26ec2 100644
--- a/libdleyna/server/props.c
+++ b/libdleyna/server/props.c
@@ -808,15 +808,10 @@ void dls_props_add_device(GUPnPDeviceInfo *root_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 *root_proxy,
GUPnPDeviceInfo *proxy,
- GUPnPServiceProxy *ems_proxy,
const dls_device_t *device,
const gchar *prop)
{
@@ -915,16 +910,6 @@ GVariant *dls_props_get_device_prop(GUPnPDeviceInfo *root_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 41f66b0..8d78817 100644
--- a/libdleyna/server/props.h
+++ b/libdleyna/server/props.h
@@ -101,7 +101,6 @@ void dls_props_add_device(GUPnPDeviceInfo *root_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 1673ccd..02909c5 100644
--- a/libdleyna/server/server.c
+++ b/libdleyna/server/server.c
@@ -976,7 +976,7 @@ gboolean dls_server_is_device_sleeping(dls_device_t *dev)
if (dev->sleeping_context != NULL)
return TRUE;
else
- return FALSE;
+ return dev->sleeping;
}
static const gchar *prv_get_device_id(const gchar *object, GError **error)