summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLouis-Francis Ratté-Boulianne <lfrb@collabora.com>2014-05-05 23:35:44 -0400
committerJens Georg <mail@jensge.org>2014-05-24 21:00:24 +0200
commit9f02229ad7322a4c5b285b393e06ddc54b56ad8c (patch)
tree5b0c026668225d4a485820a92132d435f16a90c9
parent57a6a083e7857fee0d91c28370856bcc64789d20 (diff)
downloadgssdp-9f02229ad7322a4c5b285b393e06ddc54b56ad8c.tar.gz
Add support for additionnal vendor specific headers in messages
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
-rw-r--r--libgssdp/gssdp-client.c117
-rw-r--r--libgssdp/gssdp-client.h12
-rw-r--r--libgssdp/gssdp-protocol.h8
-rw-r--r--tests/gtest/test-functional.c4
-rw-r--r--tests/gtest/test-regression.c4
5 files changed, 135 insertions, 10 deletions
diff --git a/libgssdp/gssdp-client.c b/libgssdp/gssdp-client.c
index 144ebaf..698af15 100644
--- a/libgssdp/gssdp-client.c
+++ b/libgssdp/gssdp-client.c
@@ -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);
}
diff --git a/libgssdp/gssdp-client.h b/libgssdp/gssdp-client.h
index 59a344d..ef51334 100644
--- a/libgssdp/gssdp-client.h
+++ b/libgssdp/gssdp-client.h
@@ -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__ */
diff --git a/libgssdp/gssdp-protocol.h b/libgssdp/gssdp-protocol.h
index 190bfd3..d679314 100644
--- a/libgssdp/gssdp-protocol.h
+++ b/libgssdp/gssdp-protocol.h
@@ -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"
diff --git a/tests/gtest/test-functional.c b/tests/gtest/test-functional.c
index 243caee..d1fd3ff 100644
--- a/tests/gtest/test-functional.c
+++ b/tests/gtest/test-functional.c
@@ -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;
diff --git a/tests/gtest/test-regression.c b/tests/gtest/test-regression.c
index aabba51..01a984a 100644
--- a/tests/gtest/test-regression.c
+++ b/tests/gtest/test-regression.c
@@ -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,
"",