GSSDPResourceBrowser *resource_browser;
char *usn;
GSource *timeout_src;
+ GList *locations;
} Resource;
/* Function prototypes */
stop_discovery (GSSDPResourceBrowser *resource_browser);
static gboolean
refresh_cache (gpointer data);
+static void
+resource_unavailable (GSSDPResourceBrowser *resource_browser,
+ SoupMessageHeaders *headers);
static void
gssdp_resource_browser_init (GSSDPResourceBrowser *resource_browser)
gboolean was_cached;
guint timeout;
GList *locations;
+ gboolean destroyLocations;
+ GList *it1, *it2;
char *canonical_usn;
usn = soup_message_headers_get_one (headers, "USN");
if (!usn)
return; /* No USN specified */
+ /* Build list of locations */
+ locations = NULL;
+ destroyLocations = TRUE;
+
+ header = soup_message_headers_get_one (headers, "Location");
+ if (header)
+ locations = g_list_append (locations, g_strdup (header));
+
+ header = soup_message_headers_get_one (headers, "AL");
+ if (header) {
+ /* Parse AL header. The format is:
+ * <uri1><uri2>... */
+ const char *start, *end;
+ char *uri;
+
+ start = header;
+ while ((start = strchr (start, '<'))) {
+ start += 1;
+ if (!start || !*start)
+ break;
+
+ end = strchr (start, '>');
+ if (!end || !*end)
+ break;
+
+ uri = g_strndup (start, end - start);
+ locations = g_list_append (locations, uri);
+
+ start = end;
+ }
+ }
+
+ if (!locations)
+ return; /* No location specified */
+
if (resource_browser->priv->version > 0) {
char *version;
g_strdup (canonical_usn));
}
+ /* If location does not match, expect that we missed bye bye packet */
+ if (resource) {
+ for (it1 = locations, it2 = resource->locations;
+ it1 && it2;
+ it1 = it1->next, it2 = it2->next
+ ) {
+ if (strcmp((const char *) it1->data,
+ (const char *) it2->data) != 0
+ ) {
+ resource_unavailable(resource_browser, headers);
+ resource = NULL;
+ break;
+ }
+ }
+ }
+
if (resource) {
/* Remove old timeout */
g_source_destroy (resource->timeout_src);
resource->resource_browser = resource_browser;
resource->usn = g_strdup (usn);
+ resource->locations = locations;
+ destroyLocations = FALSE; /* Ownership passed to resource */
g_hash_table_insert (resource_browser->priv->resources,
canonical_usn,
/* Only continue with signal emission if this resource was not
* cached already */
- if (was_cached)
- return;
-
- /* Build list of locations */
- locations = NULL;
-
- header = soup_message_headers_get_one (headers, "Location");
- if (header)
- locations = g_list_append (locations, g_strdup (header));
-
- header = soup_message_headers_get_one (headers, "AL");
- if (header) {
- /* Parse AL header. The format is:
- * <uri1><uri2>... */
- const char *start, *end;
- char *uri;
-
- start = header;
- while ((start = strchr (start, '<'))) {
- start += 1;
- if (!start || !*start)
- break;
-
- end = strchr (start, '>');
- if (!end || !*end)
- break;
-
- uri = g_strndup (start, end - start);
- locations = g_list_append (locations, uri);
-
- start = end;
- }
+ if (!was_cached) {
+ /* Emit signal */
+ g_signal_emit (resource_browser,
+ signals[RESOURCE_AVAILABLE],
+ 0,
+ usn,
+ locations);
}
-
- /* Emit signal */
- g_signal_emit (resource_browser,
- signals[RESOURCE_AVAILABLE],
- 0,
- usn,
- locations);
-
/* Cleanup */
- while (locations) {
- g_free (locations->data);
+ if (destroyLocations) {
+ while (locations) {
+ g_free (locations->data);
- locations = g_list_delete_link (locations, locations);
+ locations = g_list_delete_link (locations, locations);
+ }
}
}
resource_free (gpointer data)
{
Resource *resource;
-
resource = data;
+ GList *locations;
+ locations = resource->locations;
g_free (resource->usn);
g_source_destroy (resource->timeout_src);
+ while (locations) {
+ g_free (locations->data);
+ locations = g_list_delete_link (locations, locations);
+ }
+
g_slice_free (Resource, resource);
}
* ============================================================================
*/
+/* BEGIN Regression test
+ * https://bugzilla.gnome.org/show_bug.cgi?id=724030
+ * ============================================================================
+ * - Start a resource browser and send a two SSDP packets with different locations.
+ * - Check that there are 2 "resource-unavailable" signals.
+ * - Shut down the ResourceBrowser and assert that there is NO
+ * "resource-unavailable" signal.
+ */
+#define UUID_MISSED_BYE_BYE_1 "uuid:81909e94-ebf4-469e-ac68-81f2f18816ac"
+#define USN_MISSED_BYE_BYE "urn:org-gupnp:device:RegressionTestMissedByeBye:2"
+#define USN_MISSED_BYE_BYE_1 "urn:org-gupnp:device:RegressionTestMissedByeBye:1"
+#define NT_MISSED_BYE_BYE_1 UUID_MISSED_BYE_BYE_1"::"USN_MISSED_BYE_BYE_1
+#define LOCATION_MISSED_BYE_BYE_1 "http://127.0.0.1:1234"
+#define LOCATION_MISSED_BYE_BYE_2 "http://127.0.0.1:1235"
+
+char *
+create_alive_message_bgo724030 (const char *location)
+{
+ char *msg;
+
+ msg = g_strdup_printf (SSDP_ALIVE_MESSAGE,
+ 5,
+ location,
+ "",
+ "Linux/3.0 UPnP/1.0 GSSDPTesting/0.0.0",
+ NT_MISSED_BYE_BYE_1,
+ USN_MISSED_BYE_BYE_1);
+
+ return msg;
+}
+
+static gboolean
+announce_ressource_bgo724030_1 (gpointer user_data)
+{
+ send_packet (create_alive_message_bgo724030 (LOCATION_MISSED_BYE_BYE_1));
+
+ return FALSE;
+}
+
+static gboolean
+announce_ressource_bgo724030_2 (gpointer user_data)
+{
+ send_packet (create_alive_message_bgo724030 (LOCATION_MISSED_BYE_BYE_2));
+
+ return FALSE;
+}
+
+static void
+resource_availabe_bgo724030_1 (GSSDPResourceBrowser *src,
+ const char *usn,
+ GList *locations,
+ gpointer user_data)
+{
+ g_assert_cmpstr (usn, ==, USN_MISSED_BYE_BYE_1);
+ g_assert_cmpstr ((const char *) locations->data, ==, LOCATION_MISSED_BYE_BYE_1);
+ g_main_loop_quit ((GMainLoop *) user_data);
+}
+
+static void
+resource_availabe_bgo724030_2 (GSSDPResourceBrowser *src,
+ const char *usn,
+ GList *locations,
+ gpointer user_data)
+{
+ g_assert_cmpstr (usn, ==, USN_MISSED_BYE_BYE_1);
+ g_assert_cmpstr ((const char *) locations->data, ==, LOCATION_MISSED_BYE_BYE_2);
+ g_main_loop_quit ((GMainLoop *) user_data);
+}
+
+static void
+resource_unavailabe_bgo724030 (GSSDPResourceBrowser *src,
+ const char *usn,
+ gpointer user_data)
+{
+ g_assert_cmpstr (usn, ==, USN_MISSED_BYE_BYE_1);
+ g_main_loop_quit ((GMainLoop *) user_data);
+}
+
+void test_bgo724030 (void)
+{
+ GSSDPClient *dest;
+ GSSDPResourceBrowser *browser;
+ GError *error = NULL;
+ GMainLoop *loop;
+ gulong available_signal_id;
+
+ loop = g_main_loop_new (NULL, FALSE);
+
+ dest = gssdp_client_new (NULL, "lo", &error);
+ g_assert (dest != NULL);
+ g_assert (error == NULL);
+
+ browser = gssdp_resource_browser_new (dest, USN_MISSED_BYE_BYE_1);
+ available_signal_id = g_signal_connect (browser,
+ "resource-available",
+ G_CALLBACK (resource_availabe_bgo724030_1),
+ loop);
+ g_signal_connect (browser,
+ "resource-unavailable",
+ G_CALLBACK (resource_unavailabe_bgo724030),
+ loop);
+ gssdp_resource_browser_set_active (browser, TRUE);
+ g_timeout_add_seconds (2, announce_ressource_bgo724030_1, NULL);
+ g_timeout_add_seconds (3, announce_ressource_bgo724030_2, NULL);
+ g_main_loop_run (loop); /* available */
+ g_signal_handler_disconnect (browser, available_signal_id);
+ available_signal_id = g_signal_connect (browser,
+ "resource-available",
+ G_CALLBACK (resource_availabe_bgo724030_2),
+ loop);
+ g_main_loop_run (loop); /* unavailable + available */
+ g_main_loop_run (loop); /* unavailable */
+ unref_object(browser);
+}
+
+/* END Regression test
+ * https://bugzilla.gnome.org/show_bug.cgi?id=724030
+ * ============================================================================
+ */
+
+
int main (int argc, char *argv[])
{
#if !GLIB_CHECK_VERSION (2, 35, 0)
if (g_test_slow ()) {
g_test_add_func ("/bugs/gnome/673150", test_bgo673150);
g_test_add_func ("/bugs/gnome/682099", test_bgo682099);
+ g_test_add_func ("/bugs/gnome/724030", test_bgo724030);
}
g_test_run ();