[gssdp] resource-group: Implement updates



commit af99752f16710a9eda312a4560bbe6708ceafb46
Author: Jens Georg <mail jensge org>
Date:   Sun Jan 27 00:27:44 2019 +0100

    resource-group: Implement updates

 libgssdp/gssdp-protocol.h       |  10 +++
 libgssdp/gssdp-resource-group.c | 153 ++++++++++++++++++++++++++++++++--------
 libgssdp/gssdp-resource-group.h |   4 ++
 3 files changed, 138 insertions(+), 29 deletions(-)
---
diff --git a/libgssdp/gssdp-protocol.h b/libgssdp/gssdp-protocol.h
index 44bdf3b..d988c24 100644
--- a/libgssdp/gssdp-protocol.h
+++ b/libgssdp/gssdp-protocol.h
@@ -68,11 +68,21 @@ G_BEGIN_DECLS
         "NT: %s\r\n"                                \
         "USN: %s\r\n"
 
+#define SSDP_UPDATE_MESSAGE                         \
+        "NOTIFY * HTTP/1.1\r\n"                     \
+        "Host: %s:" SSDP_PORT_STR "\r\n" \
+        "Location: %s\r\n"                          \
+        "NT: %s\r\n"                                \
+        "NTS: ssdp:update\r\n"                      \
+        "USN: %s\r\n"                               \
+        "NEXTBOOTID.UPNP.ORG: %u\r\n"
+
 #define SSDP_SEARCH_METHOD "M-SEARCH"
 #define GENA_NOTIFY_METHOD "NOTIFY"
 
 #define SSDP_ALIVE_NTS  "ssdp:alive"
 #define SSDP_BYEBYE_NTS "ssdp:byebye"
+#define SSDP_UPDATE_NTS "ssdp:update"
 
 #define SSDP_DEFAULT_MAX_AGE 1800
 #define SSDP_DEFAULT_MX      3
diff --git a/libgssdp/gssdp-resource-group.c b/libgssdp/gssdp-resource-group.c
index 0301ca8..58f65b0 100644
--- a/libgssdp/gssdp-resource-group.c
+++ b/libgssdp/gssdp-resource-group.c
@@ -109,6 +109,10 @@ typedef struct {
 #define VERSION_PATTERN "[0-9]+$"
 
 /* Function prototypes */
+
+static void
+queue_message                   (GSSDPResourceGroup *resource_group,
+                                 char               *message);
 static void
 gssdp_resource_group_set_client (GSSDPResourceGroup *resource_group,
                                  GSSDPClient        *client);
@@ -512,15 +516,45 @@ send_initial_resource_byebye (Resource *resource)
 }
 
 static void
-send_announcement_set (GList *resources, GFunc message_function)
+send_announcement_set (GList *resources, GFunc message_function, gpointer user_data)
 {
         guint8 i;
 
         for (i = 0; i < DEFAULT_ANNOUNCEMENT_SET_SIZE; i++) {
-                g_list_foreach (resources, message_function, NULL);
+                g_list_foreach (resources, message_function, user_data);
         }
 }
 
+static void
+setup_reannouncement_timeout (GSSDPResourceGroup *resource_group)
+{
+        int timeout;
+        GSSDPResourceGroupPrivate *priv;
+
+        priv = gssdp_resource_group_get_instance_private (resource_group);
+
+        /* We want to re-announce at least 3 times before the resource
+         * group expires to cope with the unrelialble nature of UDP.
+         *
+         * Read the paragraphs about 'CACHE-CONTROL' on pages 21-22 of
+         * UPnP Device Architecture Document v1.1 for further details.
+         * */
+        timeout = priv->max_age;
+        if (G_LIKELY (timeout > 6))
+                timeout = (timeout / 3) - 1;
+
+        /* Add re-announcement timer */
+        priv->timeout_src = g_timeout_source_new_seconds (timeout);
+        g_source_set_callback (priv->timeout_src,
+                        resource_group_timeout,
+                        resource_group, NULL);
+
+        g_source_attach (priv->timeout_src,
+                        g_main_context_get_thread_default ());
+
+        g_source_unref (priv->timeout_src);
+}
+
 /**
  * gssdp_resource_group_set_available:
  * @resource_group: A #GSSDPResourceGroup
@@ -545,40 +579,21 @@ gssdp_resource_group_set_available (GSSDPResourceGroup *resource_group,
         priv->available = available;
 
         if (available) {
-                int timeout;
-
-                /* We want to re-announce at least 3 times before the resource
-                 * group expires to cope with the unrelialble nature of UDP.
-                 *
-                 * Read the paragraphs about 'CACHE-CONTROL' on pages 21-22 of
-                 * UPnP Device Architecture Document v1.1 for further details.
-                 * */
-                timeout = priv->max_age;
-                if (G_LIKELY (timeout > 6))
-                        timeout = (timeout / 3) - 1;
-
-                /* Add re-announcement timer */
-                priv->timeout_src = g_timeout_source_new_seconds (timeout);
-                g_source_set_callback (priv->timeout_src,
-                                       resource_group_timeout,
-                                       resource_group, NULL);
-
-                g_source_attach (priv->timeout_src,
-                                 g_main_context_get_thread_default ());
-
-                g_source_unref (priv->timeout_src);
-
+                setup_reannouncement_timeout (resource_group);
                 /* Make sure initial byebyes are sent grouped before initial
                  * alives */
                 send_announcement_set (priv->resources,
-                                       (GFunc) send_initial_resource_byebye);
+                                       (GFunc) send_initial_resource_byebye,
+                                       NULL);
 
                 send_announcement_set (priv->resources,
-                                       (GFunc) resource_alive);
+                                       (GFunc) resource_alive,
+                                       NULL);
         } else {
                 /* Unannounce all resources */
                 send_announcement_set (priv->resources,
-                                       (GFunc) resource_byebye);
+                                       (GFunc) resource_byebye,
+                                       NULL);
 
                 /* Remove re-announcement timer */
                 g_source_destroy (priv->timeout_src);
@@ -735,6 +750,86 @@ gssdp_resource_group_remove_resource (GSSDPResourceGroup *resource_group,
         }
 }
 
+static void
+resource_update (Resource *resource, gpointer user_data)
+{
+        GSSDPResourceGroupPrivate *priv;
+        GSSDPClient *client;
+        char *message;
+        const char *group;
+        char *dest;
+        guint next_boot_id = GPOINTER_TO_UINT (user_data);
+
+        priv = gssdp_resource_group_get_instance_private
+                                        (resource->resource_group);
+
+        /* Send message */
+        client = priv->client;
+
+        /* FIXME: UGLY V6 stuff */
+        group = _gssdp_client_get_mcast_group (client);
+        if (strchr (group, ':') != NULL)
+                dest = g_strdup_printf ("[%s]", group);
+        else
+                dest = g_strdup (group);
+
+        message = g_strdup_printf (SSDP_UPDATE_MESSAGE,
+                                   dest,
+                                   (char *) resource->locations->data,
+                                   resource->target,
+                                   resource->usn,
+                                   next_boot_id);
+
+        queue_message (resource->resource_group, message);
+
+        g_free (dest);
+}
+
+/**
+ * gssdp_resource_group_update:
+ * @resource_group: A #GSSDPResourceGroup
+ * @new_boot_id: The new boot id of the device
+ *
+ * Send an ssdp::update message if the underlying #GSSDPClient is running
+ * the UDA 1.1 protocol. Does nothing otherwise.
+ */
+void
+gssdp_resource_group_update (GSSDPResourceGroup *self,
+                             guint               next_boot_id)
+{
+        GSSDPUDAVersion version;
+        GSSDPResourceGroupPrivate *priv;
+
+        g_return_if_fail (GSSDP_IS_RESOURCE_GROUP (self));
+        g_return_if_fail (next_boot_id <= G_MAXINT32);
+
+        priv = gssdp_resource_group_get_instance_private (self);
+
+        version = gssdp_client_get_uda_version (priv->client);
+
+        if (version == GSSDP_UDA_VERSION_1_0)
+                return;
+
+        if (!priv->available) {
+                gssdp_client_set_boot_id (priv->client, next_boot_id);
+
+                return;
+        }
+
+        /* Disable timeout */
+        g_clear_pointer (&priv->timeout_src, g_source_destroy);
+
+        send_announcement_set (priv->resources, (GFunc) resource_update, GUINT_TO_POINTER (next_boot_id));
+
+        /* FIXME: This causes only the first of the three update messages to be correct. The other two will
+         * have the new boot id as and boot id as the same value
+         */
+        gssdp_client_set_boot_id (priv->client, next_boot_id);
+
+        setup_reannouncement_timeout (self);
+        send_announcement_set (priv->resources, (GFunc) resource_alive, NULL);
+}
+
 /*
  * Called to re-announce all resources periodically
  */
@@ -747,7 +842,7 @@ resource_group_timeout (gpointer user_data)
         resource_group = GSSDP_RESOURCE_GROUP (user_data);
         priv = gssdp_resource_group_get_instance_private (resource_group);
 
-        send_announcement_set (priv->resources, (GFunc) resource_alive);
+        send_announcement_set (priv->resources, (GFunc) resource_alive, NULL);
 
         return TRUE;
 }
diff --git a/libgssdp/gssdp-resource-group.h b/libgssdp/gssdp-resource-group.h
index 53160b6..64235e0 100644
--- a/libgssdp/gssdp-resource-group.h
+++ b/libgssdp/gssdp-resource-group.h
@@ -89,6 +89,10 @@ void
 gssdp_resource_group_remove_resource     (GSSDPResourceGroup *resource_group,
                                           guint               resource_id);
 
+void
+gssdp_resource_group_update              (GSSDPResourceGroup *resource_group,
+                                          guint               new_boot_id);
+
 G_END_DECLS
 
 #endif /* GSSDP_RESOURCE_GROUP_H */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]