Commit 91021864 authored by Parthiban Balasubramanian's avatar Parthiban Balasubramanian
Browse files

Merge branch 'master' into cablelabs/master

parents f0b7e87d 64b67f37
0.20.10
=======
Changes since 0.20.9:
- Make sure ResourceFactory creates proxies with the correct GType.
- Make it possible to unsubscribe from a service proxy during a call-back.
- Disable managed RootDevices on WL change in addition to ControlPoints.
Bugs fixed in this release:
- https://bugzilla.gnome.org/show_bug.cgi?id=678701
- https://bugzilla.gnome.org/show_bug.cgi?id=690400
- https://bugzilla.gnome.org/show_bug.cgi?id=711332
All contributors to this release:
- Jussi Kukkonen <jussi.kukkonen@intel.com>
- Jens Georg <mail@jensge.org>
0.20.9
======
Changes since 0.20.8:
- Enforce HTTP 1.1 for device description requests.
- Add libuuid to Requires.private of pkg-config file.
- Deprecate gupnp_service_proxy_{begin,send}_action_hash as they cannot
guarantee the argument order.
- Add gupnp_service_info_get_introspection_async_full() that makes it possible
to cancel an introspcetion request using GCancellable.
- Fix a crash when running with GSSDP < 0.14.6.
Bugs fixed in this release:
- https://bugzilla.gnome.org/show_bug.cgi?id=704867
- https://bugzilla.gnome.org/show_bug.cgi?id=710491
- https://bugzilla.gnome.org/show_bug.cgi?id=711027
- https://bugzilla.gnome.org/show_bug.cgi?id=711167
- https://bugzilla.gnome.org/show_bug.cgi?id=720369
- https://bugzilla.gnome.org/show_bug.cgi?id=720372
All contributors to this release:
- Jussi Kukkonen <jussi.kukkonen@intel.com>
- Jens Georg <mail@jensge.org>
- Philip Withnall <philip.withnall@collabora.co.uk>
- Parthiban Balasubramanian <p.balasubramanian@cablelabs.com>
0.20.8
======
......
AC_PREREQ([2.64])
AC_INIT([gupnp],
[0.20.9],
[0.20.11],
[http://bugzilla.gnome.org/enter_bug.cgi?product=gupnp&component=gupnp],
[gupnp],
[http://www.gupnp.org/])
......
......@@ -278,6 +278,7 @@ gupnp_service_info_get_control_url
gupnp_service_info_get_event_subscription_url
gupnp_service_info_get_introspection
gupnp_service_info_get_introspection_async
gupnp_service_info_get_introspection_async_full
<SUBSECTION Standard>
GUPnPServiceInfoClass
GUPNP_SERVICE_INFO
......
......@@ -177,20 +177,19 @@ gupnp_context_manager_filter_context (GUPnPWhiteList *white_list,
GList *obj;
GList *blk;
gboolean match;
GUPnPContext *context;
GSSDPResourceBrowser *browser;
obj = manager->priv->objects;
blk = manager->priv->blacklisted;
while (obj != NULL) {
if (!GUPNP_IS_CONTROL_POINT (obj->data))
continue;
/* If the white list is empty, treat it as disabled */
if (check) {
/* Filter out context */
context = gupnp_control_point_get_context (obj->data);
GUPnPContext *context;
g_object_get (G_OBJECT (obj->data),
"context", &context,
NULL);
match = gupnp_white_list_check_context (white_list,
context);
} else {
......@@ -198,8 +197,18 @@ gupnp_context_manager_filter_context (GUPnPWhiteList *white_list,
match = TRUE;
}
browser = GSSDP_RESOURCE_BROWSER (obj->data);
gssdp_resource_browser_set_active (browser, match);
if (GUPNP_IS_CONTROL_POINT (obj->data)) {
GSSDPResourceBrowser *browser;
browser = GSSDP_RESOURCE_BROWSER (obj->data);
gssdp_resource_browser_set_active (browser, match);
} else if (GUPNP_IS_ROOT_DEVICE (obj->data)) {
GSSDPResourceGroup *group;
group = GSSDP_RESOURCE_GROUP (obj->data);
gssdp_resource_group_set_available (group, match);
} else
g_assert_not_reached ();
obj = obj->next;
}
......
......@@ -206,7 +206,8 @@ gupnp_resource_factory_create_device_proxy
* @element: The #xmlNode ponting to the right service element
* @location: The location of the service description file
* @udn: The UDN of the device the service is contained in
* @service_type: The service type
* @service_type: (allow-none): The service type, or %NULL to use service
* type from @element
* @url_base: The URL base for this service, or %NULL if none
*
* Create a #GUPnPServiceProxy for the service with element @element, as
......@@ -225,6 +226,7 @@ gupnp_resource_factory_create_service_proxy
const char *location,
const SoupURI *url_base)
{
char *type_from_xml = NULL;
GUPnPServiceProxy *proxy;
GType proxy_type = GUPNP_TYPE_SERVICE_PROXY;
......@@ -235,6 +237,13 @@ gupnp_resource_factory_create_service_proxy
g_return_val_if_fail (location != NULL, NULL);
g_return_val_if_fail (url_base != NULL, NULL);
if (!service_type) {
type_from_xml =
xml_util_get_child_element_content_glib (element,
"serviceType");
service_type = type_from_xml;
}
if (service_type) {
gpointer value;
......@@ -254,6 +263,8 @@ gupnp_resource_factory_create_service_proxy
"element", element,
NULL);
g_free (type_from_xml);
return proxy;
}
......
......@@ -97,6 +97,7 @@ typedef struct {
GType type;
GList *callbacks;
GList *next_emit;
} NotifyData;
typedef struct {
......@@ -655,11 +656,13 @@ gupnp_service_proxy_send_action_hash (GUPnPServiceProxy *proxy,
main_loop = g_main_loop_new (g_main_context_get_thread_default (),
TRUE);
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
handle = gupnp_service_proxy_begin_action_hash (proxy,
action,
stop_main_loop,
main_loop,
in_hash);
G_GNUC_END_IGNORE_DEPRECATIONS
if (!handle) {
g_main_loop_unref (main_loop);
......@@ -1600,6 +1603,7 @@ gupnp_service_proxy_add_notify (GUPnPServiceProxy *proxy,
data->type = type;
data->callbacks = NULL;
data->next_emit = NULL;
g_hash_table_insert (proxy->priv->notify_hash,
g_strdup (variable),
......@@ -1625,6 +1629,9 @@ gupnp_service_proxy_add_notify (GUPnPServiceProxy *proxy,
data->callbacks = g_list_append (data->callbacks, callback_data);
if (data->next_emit == NULL)
data->next_emit = g_list_last (data->callbacks);
return TRUE;
}
......@@ -1637,9 +1644,10 @@ gupnp_service_proxy_add_notify (GUPnPServiceProxy *proxy,
*
* Cancels the variable change notification for @callback and @user_data.
*
* This function must not be called directly or indirectly from a
* #GUPnPServiceProxyNotifyCallback associated with this service proxy, even
* if it is for another variable.
* In version 20.9 and earlier this function must not be called directly
* or indirectly from a #GUPnPServiceProxyNotifyCallback associated with
* this service proxy, even if it is for another variable. In later
* versions such calls are allowed.
*
* Return value: %TRUE on success.
**/
......@@ -1679,6 +1687,9 @@ gupnp_service_proxy_remove_notify (GUPnPServiceProxy *proxy,
/* Gotcha! */
g_slice_free (CallbackData, callback_data);
if (data->next_emit == l)
data->next_emit = data->next_emit->next;
data->callbacks =
g_list_delete_link (data->callbacks, l);
if (data->callbacks == NULL) {
......@@ -1720,11 +1731,13 @@ emit_notification (GUPnPServiceProxy *proxy,
return;
}
/* Call callbacks */
for (l = data->callbacks; l; l = l->next) {
/* Call callbacks. Note that data->next_emit may change if
* callback calls remove_notify() or add_notify() */
for (l = data->callbacks; l; l = data->next_emit) {
CallbackData *callback_data;
callback_data = l->data;
data->next_emit = l->next;
callback_data->callback (proxy,
(const char *) var_node->name,
......
......@@ -16,4 +16,4 @@ AM_CFLAGS = \
-I $(top_srcdir) \
-DDATA_PATH="\"$(srcdir)/data\""
EXTRA_DIST=data/random4k.bin data/ServiceBgo69762.xml data/TestBgo696762.xml
EXTRA_DIST=data/random4k.bin data/TestService.xml data/TestDevice.xml
<root xmlns="urn:schemas-upnp-org:device-1-0">
<specVersion>
<major>1</major>
<minor>0</minor>
</specVersion>
<device>
<deviceType>urn:test-gupnp-org:device:TestBgo696762:1</deviceType>
<friendlyName>Regression Test for bgo#696762</friendlyName>
<modelURL>https://bugzilla.gnome.org/show_bug.cgi?id=696762</modelURL>
<UDN>uuid:1234</UDN>
<serviceList>
<service>
<serviceType>urn:test-gupnp-org:service:bgo696762:1</serviceType>
<serviceId>urn:test-gupnp-org:serviceId:bgo696762:1</serviceId>
<SCPDURL>/ServiceBgo69762.xml</SCPDURL>
<controlURL>/ServiceBgo69762/Control</controlURL>
<eventSubURL>/ServiceBgo69762/Event</eventSubURL>
</service>
</serviceList>
</device>
</root>
<root xmlns="urn:schemas-upnp-org:device-1-0">
<specVersion>
<major>1</major>
<minor>0</minor>
</specVersion>
<device>
<deviceType>urn:test-gupnp-org:device:TestDevice:1</deviceType>
<friendlyName>GUPnP Regression Test Device</friendlyName>
<modelURL>http://gupnp.org/</modelURL>
<UDN>uuid:1234</UDN>
<serviceList>
<service>
<serviceType>urn:test-gupnp-org:service:TestService:1</serviceType>
<serviceId>urn:test-gupnp-org:serviceId:TestService:1</serviceId>
<SCPDURL>/TestService.xml</SCPDURL>
<controlURL>/TestService/Control</controlURL>
<eventSubURL>/TestService/Event</eventSubURL>
</service>
</serviceList>
<deviceList>
<device>
<deviceType>urn:test-gupnp-org:device:TestSubDevice:1</deviceType>
<friendlyName>Regression Test subdevice</friendlyName>
<UDN>uuid:5678</UDN>
</device>
</deviceList>
</device>
</root>
......@@ -36,6 +36,10 @@
<name>A_ARG_TYPE_Count</name>
<dataType>ui4</dataType>
</stateVariable>
<stateVariable sendEvents="yes">
<name>evented_variable</name>
<dataType>string</dataType>
</stateVariable>
</serviceStateTable>
<actionList>
<action>
......
......@@ -44,10 +44,43 @@ struct _GUPnPServiceAction {
guint argument_count;
};
typedef struct _TestBgo696762Data {
typedef struct _TestBgo678701Service {
GUPnPServiceProxy parent_instance;
}TestBgo678701Service;
typedef struct _TestBgo678701ServiceClass
{
GUPnPServiceProxyClass parent_class;
}TestBgo678701ServiceClass;
G_DEFINE_TYPE(TestBgo678701Service, test_bgo_678701_service, GUPNP_TYPE_SERVICE_PROXY);
static void test_bgo_678701_service_class_init (TestBgo678701ServiceClass *klass) {}
static void test_bgo_678701_service_init (TestBgo678701Service *self) {}
typedef struct _TestBgo678701Device {
GUPnPDeviceProxy parent_instance;
}TestBgo678701Device;
typedef struct _TestBgo678701DeviceClass
{
GUPnPDeviceProxyClass parent_class;
}TestBgo678701DeviceClass;
G_DEFINE_TYPE(TestBgo678701Device, test_bgo_678701_device, GUPNP_TYPE_DEVICE_PROXY);
static void test_bgo_678701_device_class_init (TestBgo678701DeviceClass *klass) {}
static void test_bgo_678701_device_init (TestBgo678701Device *self) {}
typedef struct _TestServiceProxyData {
GMainLoop *loop;
GUPnPServiceProxy *proxy;
} TestBgo696762Data;
} TestServiceProxyData;
typedef struct _TestBgo678701Data {
GMainLoop *loop;
GUPnPDeviceProxy *proxy;
} TestBgo678701Data;
static void
test_bgo_696762_on_browse_call (G_GNUC_UNUSED GUPnPService *service,
......@@ -86,31 +119,88 @@ test_bgo_696762_on_browse (G_GNUC_UNUSED GUPnPServiceProxy *proxy,
G_GNUC_UNUSED GUPnPServiceProxyAction *action,
gpointer user_data)
{
TestBgo696762Data *data = (TestBgo696762Data *) user_data;
TestServiceProxyData *data = (TestServiceProxyData *) user_data;
g_main_loop_quit (data->loop);
}
static void
test_bgo_696762_on_sp_available (G_GNUC_UNUSED GUPnPControlPoint *cp,
GUPnPServiceProxy *proxy,
test_on_sp_available (G_GNUC_UNUSED GUPnPControlPoint *cp,
GUPnPServiceProxy *proxy,
gpointer user_data)
{
TestServiceProxyData *data = (TestServiceProxyData *) user_data;
data->proxy = g_object_ref (proxy);
g_main_loop_quit (data->loop);
}
static void
test_bgo_678701_on_dp_available (G_GNUC_UNUSED GUPnPControlPoint *cp,
GUPnPDeviceProxy *proxy,
gpointer user_data)
{
TestBgo696762Data *data = (TestBgo696762Data *) user_data;
TestBgo678701Data *data = (TestBgo678701Data *) user_data;
data->proxy = g_object_ref (proxy);
g_main_loop_quit (data->loop);
}
void
test_bgo_690400_notify (GUPnPServiceProxy *proxy,
const char *variable,
GValue *value,
gpointer user_data)
{
TestServiceProxyData *data = (TestServiceProxyData *) user_data;
gupnp_service_proxy_remove_notify (data->proxy,
"evented_variable",
test_bgo_690400_notify,
user_data);
}
void
test_bgo_690400_notify_too (GUPnPServiceProxy *proxy,
const char *variable,
GValue *value,
gpointer user_data)
{
TestServiceProxyData *data = (TestServiceProxyData *) user_data;
g_main_loop_quit (data->loop);
}
static void
test_bgo_690400_query_variable (GUPnPService *service,
gchar *variable,
GValue *value,
gpointer user_data)
{
g_value_init (value, G_TYPE_STRING);
g_value_set_string (value, "New Value");
}
static gboolean
test_bgo_696762_on_timeout (G_GNUC_UNUSED gpointer user_data)
test_on_timeout (G_GNUC_UNUSED gpointer user_data)
{
g_assert_not_reached ();
return FALSE;
}
static void
test_run_loop (GMainLoop *loop)
{
guint timeout_id = 0;
timeout_id = g_timeout_add_seconds (2, test_on_timeout, NULL);
g_main_loop_run (loop);
g_source_remove (timeout_id);
}
/* Test if a call on a service proxy keeps argument order */
static void
test_bgo_696762 (void)
......@@ -118,9 +208,8 @@ test_bgo_696762 (void)
GUPnPContext *context = NULL;
GError *error = NULL;
GUPnPControlPoint *cp = NULL;
guint timeout_id = 0;
GUPnPRootDevice *rd;
TestBgo696762Data data = { NULL, NULL };
TestServiceProxyData data = { NULL, NULL };
GUPnPServiceInfo *info = NULL;
data.loop = g_main_loop_new (NULL, FALSE);
......@@ -130,28 +219,26 @@ test_bgo_696762 (void)
g_assert (error == NULL);
cp = gupnp_control_point_new (context,
"urn:test-gupnp-org:service:bgo696762:1");
"urn:test-gupnp-org:service:TestService:1");
gssdp_resource_browser_set_active (GSSDP_RESOURCE_BROWSER (cp), TRUE);
g_signal_connect (G_OBJECT (cp),
"service-proxy-available",
G_CALLBACK (test_bgo_696762_on_sp_available),
G_CALLBACK (test_on_sp_available),
&data);
rd = gupnp_root_device_new (context, "TestBgo696762.xml", DATA_PATH);
rd = gupnp_root_device_new (context, "TestDevice.xml", DATA_PATH);
gupnp_root_device_set_available (rd, TRUE);
info = gupnp_device_info_get_service (GUPNP_DEVICE_INFO (rd),
"urn:test-gupnp-org:service:bgo696762:1");
"urn:test-gupnp-org:service:TestService:1");
g_signal_connect (G_OBJECT (info),
"action-invoked::Browse",
G_CALLBACK (test_bgo_696762_on_browse_call),
&data);
timeout_id = g_timeout_add_seconds (2, test_bgo_696762_on_timeout, &(data.loop));
g_main_loop_run (data.loop);
g_source_remove (timeout_id);
test_run_loop (data.loop);
g_assert (data.proxy != NULL);
gupnp_service_proxy_begin_action (data.proxy,
......@@ -166,9 +253,131 @@ test_bgo_696762 (void)
"SortCriteria", G_TYPE_STRING, "",
NULL);
timeout_id = g_timeout_add_seconds (2, test_bgo_696762_on_timeout, &(data.loop));
g_main_loop_run (data.loop);
g_source_remove (timeout_id);
test_run_loop (data.loop);
g_main_loop_unref (data.loop);
g_object_unref (data.proxy);
g_object_unref (cp);
g_object_unref (rd);
g_object_unref (context);
}
/* Test that proxies created by ResourceFactory are of the GType
* set with gupnp_resource_factory_register_resource_proxy_type().
* https://bugzilla.gnome.org/show_bug.cgi?id=678701 */
static void
test_bgo_678701 (void)
{
GUPnPContext *context = NULL;
GError *error = NULL;
GUPnPControlPoint *cp = NULL;
TestBgo678701Data data = { NULL, NULL };
GUPnPRootDevice *rd;
GUPnPServiceInfo *info = NULL;
GUPnPDeviceInfo *dev_info = NULL;
GUPnPResourceFactory *factory;
data.loop = g_main_loop_new (NULL, FALSE);
context = gupnp_context_new (NULL, "lo", 0, &error);
g_assert (context != NULL);
g_assert (error == NULL);
factory = gupnp_resource_factory_get_default ();
gupnp_resource_factory_register_resource_proxy_type (factory,
"urn:test-gupnp-org:service:TestService:1",
test_bgo_678701_service_get_type ());
gupnp_resource_factory_register_resource_proxy_type (factory,
"urn:test-gupnp-org:device:TestSubDevice:1",
test_bgo_678701_device_get_type ());
rd = gupnp_root_device_new (context, "TestDevice.xml", DATA_PATH);
gupnp_root_device_set_available (rd, TRUE);
cp = gupnp_control_point_new (context,
"urn:test-gupnp-org:device:TestDevice:1");
gssdp_resource_browser_set_active (GSSDP_RESOURCE_BROWSER (cp), TRUE);
g_signal_connect (G_OBJECT (cp),
"device-proxy-available",
G_CALLBACK (test_bgo_678701_on_dp_available),
&data);
test_run_loop (data.loop);
g_assert (data.proxy != NULL);
info = gupnp_device_info_get_service (GUPNP_DEVICE_INFO (data.proxy),
"urn:test-gupnp-org:service:TestService:1");
g_assert_cmpstr(G_OBJECT_TYPE_NAME (info), ==, "TestBgo678701Service");
dev_info = gupnp_device_info_get_device (GUPNP_DEVICE_INFO (data.proxy),
"urn:test-gupnp-org:device:TestSubDevice:1");
g_assert_cmpstr(G_OBJECT_TYPE_NAME (dev_info), ==, "TestBgo678701Device");
g_main_loop_unref (data.loop);
g_object_unref (data.proxy);
g_object_unref (cp);
g_object_unref (rd);
g_object_unref (context);
}
/* Test that removing a notify-callback from the callback itself works
* https://bugzilla.gnome.org/show_bug.cgi?id=678701 */
static void
test_bgo_690400 (void)
{
GUPnPContext *context = NULL;
GError *error = NULL;
GUPnPControlPoint *cp = NULL;
TestServiceProxyData data = { NULL, NULL };
GUPnPRootDevice *rd;
GUPnPServiceInfo *service;
data.loop = g_main_loop_new (NULL, FALSE);
context = gupnp_context_new (NULL, "lo", 0, &error);
g_assert (context != NULL);
g_assert (error == NULL);
cp = gupnp_control_point_new (context,
"urn:test-gupnp-org:service:TestService:1");
gssdp_resource_browser_set_active (GSSDP_RESOURCE_BROWSER (cp), TRUE);
g_signal_connect (G_OBJECT (cp),
"service-proxy-available",
G_CALLBACK (test_on_sp_available),
&data);
rd = gupnp_root_device_new (context, "TestDevice.xml", DATA_PATH);
service = gupnp_device_info_get_service (GUPNP_DEVICE_INFO (rd),
"urn:test-gupnp-org:service:TestService:1");
g_signal_connect (service, "query-variable",
G_CALLBACK (test_bgo_690400_query_variable), NULL);
gupnp_root_device_set_available (rd, TRUE);
test_run_loop (data.loop);
g_assert (data.proxy != NULL);
gupnp_service_proxy_add_notify (data.proxy,
"evented_variable",
G_TYPE_STRING,
(GUPnPServiceProxyNotifyCallback)test_bgo_690400_notify,
&data);
gupnp_service_proxy_add_notify (data.proxy,
"evented_variable",
G_TYPE_STRING,
(GUPnPServiceProxyNotifyCallback)test_bgo_690400_notify_too,
&data);
gupnp_service_proxy_set_subscribed (data.proxy, TRUE);
test_run_loop (data.loop);
g_main_loop_unref (data.loop);
g_object_unref (data.proxy);
g_object_unref (cp);
g_object_unref (rd);
g_object_unref (service);
g_object_unref (context);
}
int
......@@ -178,6 +387,8 @@ main (int argc, char *argv[]) {
#endif
g_test_init (&argc, &argv, NULL);
g_test_add_func ("/bugs/696762", test_bgo_696762);