Add support for additionnal vendor specific headers in messages
authorLouis-Francis Ratté-Boulianne <lfrb@collabora.com>
Tue, 6 May 2014 03:35:44 +0000 (23:35 -0400)
committerJens Georg <mail@jensge.org>
Sat, 24 May 2014 19:00:24 +0000 (21:00 +0200)
Add new API to GSSDPClient to add custom headers to every message
sent. It allows support for applications that need non-standard
headers.

https://bugzilla.gnome.org/show_bug.cgi?id=729613

libgssdp/gssdp-client.c
libgssdp/gssdp-client.h
libgssdp/gssdp-protocol.h
tests/gtest/test-functional.c
tests/gtest/test-regression.c

index 144ebaf..698af15 100644 (file)
@@ -113,12 +113,19 @@ struct _GSSDPNetworkDevice {
 };
 typedef struct _GSSDPNetworkDevice GSSDPNetworkDevice;
 
+struct _GSSDPHeaderField {
+        char *name;
+        char *value;
+};
+typedef struct _GSSDPHeaderField GSSDPHeaderField;
+
 struct _GSSDPClientPrivate {
         char              *server_id;
 
         guint              socket_ttl;
         guint              msearch_port;
         GSSDPNetworkDevice device;
+        GList             *headers;
 
         GSSDPSocketSource *request_socket;
         GSSDPSocketSource *multicast_socket;
@@ -832,6 +839,109 @@ gssdp_client_get_active (GSSDPClient *client)
         return client->priv->active;
 }
 
+static void
+header_field_free (GSSDPHeaderField *header)
+{
+        g_free (header->name);
+        g_free (header->value);
+        g_slice_free (GSSDPHeaderField, header);
+}
+
+static gchar *
+append_header_fields (GSSDPClient *client,
+                      const gchar *message)
+{
+        GString *str;
+        GList *iter;
+
+        str = g_string_new (message);
+
+        for (iter = client->priv->headers; iter; iter = iter->next) {
+                GSSDPHeaderField *header = (GSSDPHeaderField *) iter->data;
+                g_string_append_printf (str, "%s: %s\r\n",
+                                        header->name,
+                                        header->value ?: "");
+        }
+
+        g_string_append (str, "\r\n");
+
+        return g_string_free (str, FALSE);
+}
+
+/**
+ * gssdp_client_append_header:
+ * @client: A #GSSDPClient
+ * @name: Header name
+ * @value: Header value
+ *
+ * Adds a header field to the message sent by this @client. It is intended to
+ * be used by clients requiring vendor specific header fields. (If there is an
+ * existing header with name name , then this creates a second one).
+ **/
+void
+gssdp_client_append_header (GSSDPClient *client,
+                            const char  *name,
+                            const char  *value)
+{
+        GSSDPHeaderField *header;
+
+        g_return_if_fail (GSSDP_IS_CLIENT (client));
+        g_return_if_fail (name != NULL);
+
+        header = g_slice_new (GSSDPHeaderField);
+        header->name = g_strdup (name);
+        header->value = g_strdup (value);
+        client->priv->headers = g_list_append (client->priv->headers, header);
+}
+
+/**
+ * gssdp_client_remove_header:
+ * @client: A #GSSDPClient
+ * @name: Header name
+ *
+ * Removes @name from the list of headers . If there are multiple values for
+ * @name, they are all removed.
+ **/
+void
+gssdp_client_remove_header (GSSDPClient *client,
+                            const char  *name)
+{
+        GSSDPClientPrivate *priv;
+        GList *l;
+
+        g_return_if_fail (GSSDP_IS_CLIENT (client));
+        g_return_if_fail (name != NULL);
+
+        priv = client->priv;
+        l = priv->headers;
+        while (l != NULL)
+        {
+                GList *next = l->next;
+                GSSDPHeaderField *header = l->data;
+
+                if (!g_strcmp0 (header->name, name)) {
+                        header_field_free (header);
+                        priv->headers = g_list_delete_link (priv->headers, l);
+                }
+                l = next;
+        }
+}
+
+/**
+ * gssdp_client_clear_headers:
+ * @client: A #GSSDPClient
+ *
+ * Removes all the headers for this @client.
+ **/
+void
+gssdp_client_clear_headers (GSSDPClient *client)
+{
+        g_return_if_fail (GSSDP_IS_CLIENT (client));
+
+        g_list_free_full (client->priv->headers,
+                          (GDestroyNotify) header_field_free);
+}
+
 /**
  * _gssdp_client_send_message:
  * @client: A #GSSDPClient
@@ -853,6 +963,7 @@ _gssdp_client_send_message (GSSDPClient      *client,
         GInetAddress *inet_address = NULL;
         GSocketAddress *address = NULL;
         GSocket *socket;
+        char *extended_message;
 
         g_return_if_fail (GSSDP_IS_CLIENT (client));
         g_return_if_fail (message != NULL);
@@ -878,11 +989,12 @@ _gssdp_client_send_message (GSSDPClient      *client,
 
         inet_address = g_inet_address_new_from_string (dest_ip);
         address = g_inet_socket_address_new (inet_address, dest_port);
+        extended_message = append_header_fields (client, message);
 
         res = g_socket_send_to (socket,
                                 address,
-                                message,
-                                strlen (message),
+                                extended_message,
+                                strlen (extended_message),
                                 NULL,
                                 &error);
 
@@ -893,6 +1005,7 @@ _gssdp_client_send_message (GSSDPClient      *client,
                 g_error_free (error);
         }
 
+        g_free (extended_message);
         g_object_unref (address);
         g_object_unref (inet_address);
 }
index 59a344d..ef51334 100644 (file)
@@ -108,6 +108,18 @@ gssdp_client_get_network      (GSSDPClient  *client);
 gboolean
 gssdp_client_get_active       (GSSDPClient  *client);
 
+void
+gssdp_client_append_header    (GSSDPClient *client,
+                               const char  *name,
+                               const char  *value);
+
+void
+gssdp_client_remove_header    (GSSDPClient *client,
+                               const char  *name);
+
+void
+gssdp_client_clear_headers    (GSSDPClient *client);
+
 G_END_DECLS
 
 #endif /* __GSSDP_CLIENT_H__ */
index 190bfd3..d679314 100644 (file)
@@ -34,7 +34,7 @@ G_BEGIN_DECLS
         "Man: \"ssdp:discover\"\r\n"                \
         "ST: %s\r\n"                                \
         "MX: %d\r\n"                                \
-        "User-Agent: %s GSSDP/" VERSION "\r\n\r\n"  \
+        "User-Agent: %s GSSDP/" VERSION "\r\n"  \
 
 #define SSDP_DISCOVERY_RESPONSE                     \
         "HTTP/1.1 200 OK\r\n"                       \
@@ -46,7 +46,7 @@ G_BEGIN_DECLS
         "Cache-Control: max-age=%d\r\n"             \
         "ST: %s\r\n"                                \
         "Date: %s\r\n"                              \
-        "Content-Length: 0\r\n\r\n"
+        "Content-Length: 0\r\n"
 
 #define SSDP_ALIVE_MESSAGE                          \
         "NOTIFY * HTTP/1.1\r\n"                     \
@@ -57,14 +57,14 @@ G_BEGIN_DECLS
         "Server: %s\r\n"                            \
         "NTS: ssdp:alive\r\n"                       \
         "NT: %s\r\n"                                \
-        "USN: %s\r\n\r\n"
+        "USN: %s\r\n"
 
 #define SSDP_BYEBYE_MESSAGE                         \
         "NOTIFY * HTTP/1.1\r\n"                     \
         "Host: " SSDP_ADDR ":" SSDP_PORT_STR "\r\n" \
         "NTS: ssdp:byebye\r\n"                     \
         "NT: %s\r\n"                                \
-        "USN: %s\r\n\r\n"
+        "USN: %s\r\n"
 
 #define SSDP_SEARCH_METHOD "M-SEARCH"
 #define GENA_NOTIFY_METHOD "NOTIFY"
index 243caee..d1fd3ff 100644 (file)
@@ -71,7 +71,7 @@ create_alive_message (const char *nt)
         else
                 usn = g_strconcat (UUID_1, "::", nt, NULL);
 
-        msg = g_strdup_printf (SSDP_ALIVE_MESSAGE,
+        msg = g_strdup_printf (SSDP_ALIVE_MESSAGE "\r\n",
                                1800,
                                "http://127.0.0.1:1234",
                                "",
@@ -93,7 +93,7 @@ create_byebye_message (const char *nt)
         else
                 usn = g_strconcat (UUID_1, "::", nt, NULL);
 
-        msg = g_strdup_printf (SSDP_BYEBYE_MESSAGE, nt, usn);
+        msg = g_strdup_printf (SSDP_BYEBYE_MESSAGE "\r\n", nt, usn);
         g_free (usn);
 
         return msg;
index aabba51..01a984a 100644 (file)
@@ -71,7 +71,7 @@ create_alive_message (const char *nt, int max_life)
         else
                 usn = g_strconcat (UUID_1, "::", nt, NULL);
 
-        msg = g_strdup_printf (SSDP_ALIVE_MESSAGE,
+        msg = g_strdup_printf (SSDP_ALIVE_MESSAGE "\r\n",
                                max_life,
                                "http://127.0.0.1:1234",
                                "",
@@ -268,7 +268,7 @@ create_alive_message_bgo724030 (const char *location)
 {
         char *msg;
 
-        msg = g_strdup_printf (SSDP_ALIVE_MESSAGE,
+        msg = g_strdup_printf (SSDP_ALIVE_MESSAGE "\r\n",
                                5,
                                location,
                                "",