From c60ec4fb2df0e9a67f3bf6c7b9e0436e9c73de6c Mon Sep 17 00:00:00 2001 From: Ludovic Ferrandis Date: Mon, 16 Sep 2013 15:20:26 +0200 Subject: [Path] Make object paths stable across restarts Fix issue #114: Root paths for servers were builded using an incremental counter, based of the discovery order made by GSSDP: Results were of this form: /com/intel/dLeynaRenderer/server/0 /com/intel/dLeynaRenderer/server/1 Object paths were builded on these root paths: /com/intel/dLeynaRenderer/server/0/xxxxxxxxxx There is no persistence between restarts of dleyna because we can't assign the same index to the same server. To fix this issue, we replace the volatile part of the root path, id the index, by a non volatile and unique part, id the server udn. The server udn is a string of this form: "uuid:" is defined by RFC 4122( and it's composed only with hex digit and char '-' To make the path compatible with dbus and 'reversible': 1 - remove the prefix 'uuid:' 2 - convert '-' char to '_' char Result is of the form below: /com/intel/dLeynaRenderer/server/99951d71_23d5_5525_94eb_a4aa78a98211 This path is stable accross dleyna restart and identify uniquely a server. This can be sued to save object path and to use them after multiple restart of the server and dLeyna. Signed-off-by: Ludovic Ferrandis --- libdleyna/renderer/device.c | 12 ++++++++++-- libdleyna/renderer/device.h | 2 +- libdleyna/renderer/upnp.c | 7 +------ 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/libdleyna/renderer/device.c b/libdleyna/renderer/device.c index d5aa82c..f2766e1 100644 --- a/libdleyna/renderer/device.c +++ b/libdleyna/renderer/device.c @@ -820,18 +820,26 @@ dlr_device_t *dlr_device_new( dleyna_connector_id_t connection, GUPnPDeviceProxy *proxy, const gchar *ip_address, - guint counter, + const char *udn, const dleyna_connector_dispatch_cb_t *dispatch_table, const dleyna_task_queue_key_t *queue_id) { dlr_device_t *dev; gchar *new_path; + gchar *uuid; dlr_device_context_t *context; DLEYNA_LOG_DEBUG("New Device on %s", ip_address); - new_path = g_strdup_printf("%s/%u", DLEYNA_SERVER_PATH, counter); + /* Strip 'uuid:' string prefix if exists and replace unauthorized + * dbus path char from uuid string */ + uuid = strchr(udn, ':'); + uuid = g_strdup(uuid ? uuid + 1 : udn); + uuid = g_strdelimit(uuid, "-", '_'); + + new_path = g_strdup_printf("%s/%s", DLEYNA_SERVER_PATH, uuid); DLEYNA_LOG_DEBUG("Server Path %s", new_path); + g_free(uuid); dev = g_new0(dlr_device_t, 1); diff --git a/libdleyna/renderer/device.h b/libdleyna/renderer/device.h index 70692f3..dd39081 100644 --- a/libdleyna/renderer/device.h +++ b/libdleyna/renderer/device.h @@ -101,7 +101,7 @@ dlr_device_t *dlr_device_new( dleyna_connector_id_t connection, GUPnPDeviceProxy *proxy, const gchar *ip_address, - guint counter, + const char *udn, const dleyna_connector_dispatch_cb_t *dispatch_table, const dleyna_task_queue_key_t *queue_id); diff --git a/libdleyna/renderer/upnp.c b/libdleyna/renderer/upnp.c index fefc340..bd9a688 100644 --- a/libdleyna/renderer/upnp.c +++ b/libdleyna/renderer/upnp.c @@ -45,7 +45,6 @@ struct dlr_upnp_t_ { void *user_data; GHashTable *server_udn_map; GHashTable *server_uc_map; - guint counter; dlr_host_service_t *host_service; }; @@ -186,14 +185,10 @@ static void prv_server_available_cb(GUPnPControlPoint *cp, queue_id = prv_create_device_queue(&priv_t); device = dlr_device_new(upnp->connection, proxy, ip_address, - upnp->counter, - upnp->interface_info, - queue_id); + udn, upnp->interface_info, queue_id); prv_update_device_context(priv_t, upnp, udn, device, ip_address, queue_id); - - upnp->counter++; } else { DLEYNA_LOG_DEBUG("Device Found"); -- cgit v1.2.1 From 953fafd6dd563bf3e4d17a8dbaa5d85a33c40979 Mon Sep 17 00:00:00 2001 From: Ludovic Ferrandis Date: Mon, 16 Sep 2013 15:26:47 +0200 Subject: [Deprecated API] Use new API instead of deprecated Use instead gssdp_client_get_host_ip of gupnp_context_get_host_ip Signed-off-by: Ludovic Ferrandis --- libdleyna/renderer/upnp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libdleyna/renderer/upnp.c b/libdleyna/renderer/upnp.c index bd9a688..7195d46 100644 --- a/libdleyna/renderer/upnp.c +++ b/libdleyna/renderer/upnp.c @@ -161,8 +161,8 @@ static void prv_server_available_cb(GUPnPControlPoint *cp, udn = gupnp_device_info_get_udn((GUPnPDeviceInfo *)proxy); - ip_address = gupnp_context_get_host_ip( - gupnp_control_point_get_context(cp)); + ip_address = gssdp_client_get_host_ip( + GSSDP_CLIENT(gupnp_control_point_get_context(cp))); if (!udn || !ip_address) goto on_error; -- cgit v1.2.1 From 6c93a242449a79d7fd89d7377e5618bc17e1f237 Mon Sep 17 00:00:00 2001 From: Ludovic Ferrandis Date: Tue, 17 Sep 2013 14:52:50 +0200 Subject: to fix up Signed-off-by: Ludovic Ferrandis --- libdleyna/renderer/device.c | 56 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 49 insertions(+), 7 deletions(-) diff --git a/libdleyna/renderer/device.c b/libdleyna/renderer/device.c index f2766e1..3a5a883 100644 --- a/libdleyna/renderer/device.c +++ b/libdleyna/renderer/device.c @@ -816,6 +816,52 @@ void dlr_device_construct( DLEYNA_LOG_DEBUG("Exit"); } +static char *prv_convert_udn_to_path(const char *udn) +{ + char *uuid; + size_t len; + size_t dest_len; + size_t i; + + /* This function will generate a valid dbus path from the udn + * We are not going to check the UDN validity. We will try to + * convert it anyway. To avoid any security problem, we will + * check some limits and possibily return only a partial + * UDN. For a better understanding, a valid UDN should be: + * UDN = "uuid:4Hex-2Hex-2Hex-Hex-Hex-6Hex" + * + * The convertion rules are: + * 1 - An invalid char will be escaped using its hexa representation + * prefixed with '_': Ex ':' -> '_3A' + * 2 - The max size of the converted UDN can be 3 times the original + * size (if all char are not dbus compliant). + * The max size of a dbus path is an UINT32: G_MAXUINT32 + * We will limit the of the converted string size to G_MAXUINT32 / 2 + * otherwise we will never have space to generate object path. + */ + + len = strlen(udn); + dest_len = MIN(len * 3, G_MAXUINT32 / 2); + + uuid = g_malloc(dest_len + 1); + i = 0; + + while (*udn && (i < dest_len)) + { + if (g_ascii_isalnum(*udn) || (*udn == '_')) + uuid[i++] = *udn; + else + i += g_snprintf(uuid + i, dest_len + 1,"_%02x", *udn); + + udn++; + } + + + uuid[i]=0; + + return uuid; +} + dlr_device_t *dlr_device_new( dleyna_connector_id_t connection, GUPnPDeviceProxy *proxy, @@ -831,16 +877,12 @@ dlr_device_t *dlr_device_new( DLEYNA_LOG_DEBUG("New Device on %s", ip_address); - /* Strip 'uuid:' string prefix if exists and replace unauthorized - * dbus path char from uuid string */ - uuid = strchr(udn, ':'); - uuid = g_strdup(uuid ? uuid + 1 : udn); - uuid = g_strdelimit(uuid, "-", '_'); - + uuid = prv_convert_udn_to_path(udn); new_path = g_strdup_printf("%s/%s", DLEYNA_SERVER_PATH, uuid); - DLEYNA_LOG_DEBUG("Server Path %s", new_path); g_free(uuid); + DLEYNA_LOG_DEBUG("Server Path %s", new_path); + dev = g_new0(dlr_device_t, 1); dev->connection = connection; -- cgit v1.2.1