[gssdp] Recover from lost bye bye packets.
- From: Jens Georg <jensgeorg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gssdp] Recover from lost bye bye packets.
- Date: Sat, 15 Mar 2014 08:00:19 +0000 (UTC)
commit 9c499f0dfa30c0c97e9a8eb7a94b28e8e2fce5c6
Author: Branislav Katreniak <bkatreniak nuvotechnologies com>
Date: Fri Feb 14 12:25:37 2014 +0100
Recover from lost bye bye packets.
When ssdp server is forcefully stopped and started again,
it sends BYE BYE packets at its start.
But if server does not follow SSDP specification
or if we miss the BYE BYE packets for any other reason,
gssdp_resource_browser believes that the server was never restarted.
If location changed after server restart,
we are not able to talk to the server any more.
This patch checks whether location matches previous location.
If not, BYE BYE packet is simulated.
Compared to the previous code, ssdp:alive packets with no location
and no AL are dropped.
Signed-off-by: Branislav Katreniak <bkatreniak nuvotechnologies com>
https://bugzilla.gnome.org/show_bug.cgi?id=724030
libgssdp/gssdp-resource-browser.c | 122 +++++++++++++++++++++++-------------
tests/gtest/test-regression.c | 122 +++++++++++++++++++++++++++++++++++++
2 files changed, 200 insertions(+), 44 deletions(-)
---
diff --git a/libgssdp/gssdp-resource-browser.c b/libgssdp/gssdp-resource-browser.c
index 7db5d1f..5aaa3d0 100644
--- a/libgssdp/gssdp-resource-browser.c
+++ b/libgssdp/gssdp-resource-browser.c
@@ -91,6 +91,7 @@ typedef struct {
GSSDPResourceBrowser *resource_browser;
char *usn;
GSource *timeout_src;
+ GList *locations;
} Resource;
/* Function prototypes */
@@ -118,6 +119,9 @@ static void
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)
@@ -679,12 +683,49 @@ resource_available (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;
@@ -704,6 +745,22 @@ resource_available (GSSDPResourceBrowser *resource_browser,
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);
@@ -715,6 +772,8 @@ resource_available (GSSDPResourceBrowser *resource_browser,
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,
@@ -804,52 +863,21 @@ resource_available (GSSDPResourceBrowser *resource_browser,
/* 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);
+ }
}
}
@@ -1016,13 +1044,19 @@ static void
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);
}
diff --git a/tests/gtest/test-regression.c b/tests/gtest/test-regression.c
index a68e44c..aabba51 100644
--- a/tests/gtest/test-regression.c
+++ b/tests/gtest/test-regression.c
@@ -248,6 +248,127 @@ void test_bgo682099 (void)
* ============================================================================
*/
+/* 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)
@@ -258,6 +379,7 @@ int main (int argc, char *argv[])
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 ();
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]