From 9f02229ad7322a4c5b285b393e06ddc54b56ad8c Mon Sep 17 00:00:00 2001 From: =?utf8?q?Louis-Francis=20Ratt=C3=A9-Boulianne?= Date: Mon, 5 May 2014 23:35:44 -0400 Subject: [PATCH] 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 --- libgssdp/gssdp-client.c | 117 +++++++++++++++++++++++++++++++++++++++++- libgssdp/gssdp-client.h | 12 +++++ libgssdp/gssdp-protocol.h | 8 +-- tests/gtest/test-functional.c | 4 +- tests/gtest/test-regression.c | 4 +- 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, "", -- 2.7.4