mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-24 22:46:15 +01:00
gsocketconnectable: Add a to_string() virtual method
Add string serialisation functions for GNetworkAddress, GSocketAddress, GUnixSocketAddress, GInetSocketAddress, GNetworkService and GSocketConnectable. These are intended for use in debug output, not for serialisation in network or disc protocols. They are implemented as a new virtual method on GSocketConnectable: g_socket_connectable_to_string(). GInetSocketAddress and GUnixSocketAddress now implement GSocketConnectable directly to implement to_string(). Previously they implemented it via their abstract parent class, GSocketAddress. https://bugzilla.gnome.org/show_bug.cgi?id=737116
This commit is contained in:
parent
4e631d2e5f
commit
128c413261
@ -1915,6 +1915,7 @@ GSocketConnectable
|
||||
GSocketConnectableIface
|
||||
g_socket_connectable_enumerate
|
||||
g_socket_connectable_proxy_enumerate
|
||||
g_socket_connectable_to_string
|
||||
<SUBSECTION>
|
||||
GSocketAddressEnumerator
|
||||
g_socket_address_enumerator_next
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "ginetsocketaddress.h"
|
||||
#include "ginetaddress.h"
|
||||
#include "gnetworkingprivate.h"
|
||||
#include "gsocketconnectable.h"
|
||||
#include "gioerror.h"
|
||||
#include "glibintl.h"
|
||||
|
||||
@ -54,7 +55,13 @@ struct _GInetSocketAddressPrivate
|
||||
guint32 scope_id;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (GInetSocketAddress, g_inet_socket_address, G_TYPE_SOCKET_ADDRESS)
|
||||
static void g_inet_socket_address_connectable_iface_init (GSocketConnectableIface *iface);
|
||||
static gchar *g_inet_socket_address_connectable_to_string (GSocketConnectable *connectable);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GInetSocketAddress, g_inet_socket_address, G_TYPE_SOCKET_ADDRESS,
|
||||
G_ADD_PRIVATE (GInetSocketAddress)
|
||||
G_IMPLEMENT_INTERFACE (G_TYPE_SOCKET_CONNECTABLE,
|
||||
g_inet_socket_address_connectable_iface_init))
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
@ -301,6 +308,59 @@ g_inet_socket_address_class_init (GInetSocketAddressClass *klass)
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
}
|
||||
|
||||
static void
|
||||
g_inet_socket_address_connectable_iface_init (GSocketConnectableIface *iface)
|
||||
{
|
||||
GSocketConnectableIface *parent_iface = g_type_interface_peek_parent (iface);
|
||||
|
||||
iface->enumerate = parent_iface->enumerate;
|
||||
iface->proxy_enumerate = parent_iface->proxy_enumerate;
|
||||
iface->to_string = g_inet_socket_address_connectable_to_string;
|
||||
}
|
||||
|
||||
static gchar *
|
||||
g_inet_socket_address_connectable_to_string (GSocketConnectable *connectable)
|
||||
{
|
||||
GInetSocketAddress *sa;
|
||||
GInetAddress *a;
|
||||
gchar *a_string;
|
||||
GString *out;
|
||||
guint16 port;
|
||||
|
||||
sa = G_INET_SOCKET_ADDRESS (connectable);
|
||||
a = g_inet_socket_address_get_address (sa);
|
||||
out = g_string_new ("");
|
||||
|
||||
/* Address. */
|
||||
a_string = g_inet_address_to_string (a);
|
||||
g_string_append (out, a_string);
|
||||
g_free (a_string);
|
||||
|
||||
/* Scope ID (IPv6 only). */
|
||||
if (g_inet_address_get_family (a) == G_SOCKET_FAMILY_IPV6 &&
|
||||
g_inet_socket_address_get_scope_id (sa) != 0)
|
||||
{
|
||||
g_string_append_printf (out, "%%%u",
|
||||
g_inet_socket_address_get_scope_id (sa));
|
||||
}
|
||||
|
||||
/* Port. */
|
||||
port = g_inet_socket_address_get_port (sa);
|
||||
if (port != 0)
|
||||
{
|
||||
/* Disambiguate ports from IPv6 addresses using square brackets. */
|
||||
if (g_inet_address_get_family (a) == G_SOCKET_FAMILY_IPV6)
|
||||
{
|
||||
g_string_prepend (out, "[");
|
||||
g_string_append (out, "]");
|
||||
}
|
||||
|
||||
g_string_append_printf (out, ":%u", port);
|
||||
}
|
||||
|
||||
return g_string_free (out, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
g_inet_socket_address_init (GInetSocketAddress *address)
|
||||
{
|
||||
|
@ -86,6 +86,7 @@ static void g_network_address_get_property (GObject *object,
|
||||
static void g_network_address_connectable_iface_init (GSocketConnectableIface *iface);
|
||||
static GSocketAddressEnumerator *g_network_address_connectable_enumerate (GSocketConnectable *connectable);
|
||||
static GSocketAddressEnumerator *g_network_address_connectable_proxy_enumerate (GSocketConnectable *connectable);
|
||||
static gchar *g_network_address_connectable_to_string (GSocketConnectable *connectable);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GNetworkAddress, g_network_address, G_TYPE_OBJECT,
|
||||
G_ADD_PRIVATE (GNetworkAddress)
|
||||
@ -145,6 +146,7 @@ g_network_address_connectable_iface_init (GSocketConnectableIface *connectable_i
|
||||
{
|
||||
connectable_iface->enumerate = g_network_address_connectable_enumerate;
|
||||
connectable_iface->proxy_enumerate = g_network_address_connectable_proxy_enumerate;
|
||||
connectable_iface->to_string = g_network_address_connectable_to_string;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1111,3 +1113,27 @@ g_network_address_connectable_proxy_enumerate (GSocketConnectable *connectable)
|
||||
|
||||
return proxy_enum;
|
||||
}
|
||||
|
||||
static gchar *
|
||||
g_network_address_connectable_to_string (GSocketConnectable *connectable)
|
||||
{
|
||||
GNetworkAddress *addr;
|
||||
const gchar *scheme;
|
||||
guint16 port;
|
||||
GString *out; /* owned */
|
||||
|
||||
addr = G_NETWORK_ADDRESS (connectable);
|
||||
out = g_string_new ("");
|
||||
|
||||
scheme = g_network_address_get_scheme (addr);
|
||||
if (scheme != NULL)
|
||||
g_string_append_printf (out, "%s:", scheme);
|
||||
|
||||
g_string_append (out, g_network_address_get_hostname (addr));
|
||||
|
||||
port = g_network_address_get_port (addr);
|
||||
if (port != 0)
|
||||
g_string_append_printf (out, ":%u", port);
|
||||
|
||||
return g_string_free (out, FALSE);
|
||||
}
|
||||
|
@ -89,6 +89,7 @@ static void g_network_service_get_property (GObject *object,
|
||||
static void g_network_service_connectable_iface_init (GSocketConnectableIface *iface);
|
||||
static GSocketAddressEnumerator *g_network_service_connectable_enumerate (GSocketConnectable *connectable);
|
||||
static GSocketAddressEnumerator *g_network_service_connectable_proxy_enumerate (GSocketConnectable *connectable);
|
||||
static gchar *g_network_service_connectable_to_string (GSocketConnectable *connectable);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GNetworkService, g_network_service, G_TYPE_OBJECT,
|
||||
G_ADD_PRIVATE (GNetworkService)
|
||||
@ -159,6 +160,7 @@ g_network_service_connectable_iface_init (GSocketConnectableIface *connectable_i
|
||||
{
|
||||
connectable_iface->enumerate = g_network_service_connectable_enumerate;
|
||||
connectable_iface->proxy_enumerate = g_network_service_connectable_proxy_enumerate;
|
||||
connectable_iface->to_string = g_network_service_connectable_to_string;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -743,3 +745,15 @@ g_network_service_connectable_proxy_enumerate (GSocketConnectable *connectable)
|
||||
|
||||
return addr_enum;
|
||||
}
|
||||
|
||||
static gchar *
|
||||
g_network_service_connectable_to_string (GSocketConnectable *connectable)
|
||||
{
|
||||
GNetworkService *service;
|
||||
|
||||
service = G_NETWORK_SERVICE (connectable);
|
||||
|
||||
return g_strdup_printf ("(%s, %s, %s, %s)", service->priv->service,
|
||||
service->priv->protocol, service->priv->domain,
|
||||
service->priv->scheme);
|
||||
}
|
||||
|
@ -129,6 +129,7 @@ g_socket_address_connectable_iface_init (GSocketConnectableIface *connectable_if
|
||||
{
|
||||
connectable_iface->enumerate = g_socket_address_connectable_enumerate;
|
||||
connectable_iface->proxy_enumerate = g_socket_address_connectable_proxy_enumerate;
|
||||
/* to_string() is implemented by subclasses */
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -146,3 +146,34 @@ g_socket_connectable_proxy_enumerate (GSocketConnectable *connectable)
|
||||
else
|
||||
return (* iface->enumerate) (connectable);
|
||||
}
|
||||
|
||||
/**
|
||||
* g_socket_connectable_to_string:
|
||||
* @connectable: a #GSocketConnectable
|
||||
*
|
||||
* Format a #GSocketConnectable as a string. This is a human-readable format for
|
||||
* use in debugging output, and is not a stable serialization format. It is not
|
||||
* suitable for use in user interfaces as it exposes too much information for a
|
||||
* user.
|
||||
*
|
||||
* If the #GSocketConnectable implementation does not support string formatting,
|
||||
* the implementation’s type name will be returned as a fallback.
|
||||
*
|
||||
* Returns: (transfer full): the formatted string
|
||||
*
|
||||
* Since: 2.48.0
|
||||
*/
|
||||
gchar *
|
||||
g_socket_connectable_to_string (GSocketConnectable *connectable)
|
||||
{
|
||||
GSocketConnectableIface *iface;
|
||||
|
||||
g_return_val_if_fail (G_IS_SOCKET_CONNECTABLE (connectable), NULL);
|
||||
|
||||
iface = G_SOCKET_CONNECTABLE_GET_IFACE (connectable);
|
||||
|
||||
if (iface->to_string != NULL)
|
||||
return iface->to_string (connectable);
|
||||
else
|
||||
return g_strdup (G_OBJECT_TYPE_NAME (connectable));
|
||||
}
|
||||
|
@ -44,6 +44,8 @@ typedef struct _GSocketConnectableIface GSocketConnectableIface;
|
||||
* @g_iface: The parent interface.
|
||||
* @enumerate: Creates a #GSocketAddressEnumerator
|
||||
* @proxy_enumerate: Creates a #GProxyAddressEnumerator
|
||||
* @to_string: Format the connectable’s address as a string for debugging.
|
||||
* Implementing this is optional. (Since: 2.48.0.)
|
||||
*
|
||||
* Provides an interface for returning a #GSocketAddressEnumerator
|
||||
* and #GProxyAddressEnumerator
|
||||
@ -58,6 +60,7 @@ struct _GSocketConnectableIface
|
||||
|
||||
GSocketAddressEnumerator * (* proxy_enumerate) (GSocketConnectable *connectable);
|
||||
|
||||
gchar * (* to_string) (GSocketConnectable *connectable);
|
||||
};
|
||||
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
@ -69,6 +72,9 @@ GSocketAddressEnumerator *g_socket_connectable_enumerate (GSocketConnectable *co
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
GSocketAddressEnumerator *g_socket_connectable_proxy_enumerate (GSocketConnectable *connectable);
|
||||
|
||||
GLIB_AVAILABLE_IN_2_48
|
||||
gchar *g_socket_connectable_to_string (GSocketConnectable *addr);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "gunixsocketaddress.h"
|
||||
#include "gsocketconnectable.h"
|
||||
#include "glibintl.h"
|
||||
#include "gnetworking.h"
|
||||
|
||||
@ -76,7 +77,13 @@ struct _GUnixSocketAddressPrivate
|
||||
GUnixSocketAddressType address_type;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (GUnixSocketAddress, g_unix_socket_address, G_TYPE_SOCKET_ADDRESS)
|
||||
static void g_unix_socket_address_connectable_iface_init (GSocketConnectableIface *iface);
|
||||
static gchar *g_unix_socket_address_connectable_to_string (GSocketConnectable *connectable);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GUnixSocketAddress, g_unix_socket_address, G_TYPE_SOCKET_ADDRESS,
|
||||
G_ADD_PRIVATE (GUnixSocketAddress)
|
||||
G_IMPLEMENT_INTERFACE (G_TYPE_SOCKET_CONNECTABLE,
|
||||
g_unix_socket_address_connectable_iface_init))
|
||||
|
||||
static void
|
||||
g_unix_socket_address_set_property (GObject *object,
|
||||
@ -299,6 +306,49 @@ g_unix_socket_address_class_init (GUnixSocketAddressClass *klass)
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
}
|
||||
|
||||
static void
|
||||
g_unix_socket_address_connectable_iface_init (GSocketConnectableIface *iface)
|
||||
{
|
||||
GSocketConnectableIface *parent_iface = g_type_interface_peek_parent (iface);
|
||||
|
||||
iface->enumerate = parent_iface->enumerate;
|
||||
iface->proxy_enumerate = parent_iface->proxy_enumerate;
|
||||
iface->to_string = g_unix_socket_address_connectable_to_string;
|
||||
}
|
||||
|
||||
static gchar *
|
||||
g_unix_socket_address_connectable_to_string (GSocketConnectable *connectable)
|
||||
{
|
||||
GUnixSocketAddress *ua;
|
||||
GString *out;
|
||||
const gchar *path;
|
||||
gsize path_len, i;
|
||||
|
||||
ua = G_UNIX_SOCKET_ADDRESS (connectable);
|
||||
|
||||
/* Anonymous sockets have no path. */
|
||||
if (ua->priv->address_type == G_UNIX_SOCKET_ADDRESS_ANONYMOUS)
|
||||
return g_strdup ("anonymous");
|
||||
|
||||
path = g_unix_socket_address_get_path (ua);
|
||||
path_len = g_unix_socket_address_get_path_len (ua);
|
||||
out = g_string_sized_new (path_len);
|
||||
|
||||
/* Return the #GUnixSocketAddress:path, but with all non-printable characters
|
||||
* (including nul bytes) escaped to hex. */
|
||||
for (i = 0; i < path_len; i++)
|
||||
{
|
||||
guint8 c = path[i];
|
||||
|
||||
if (g_ascii_isprint (path[i]))
|
||||
g_string_append_c (out, c);
|
||||
else
|
||||
g_string_append_printf (out, "\\x%02x", (guint) c);
|
||||
}
|
||||
|
||||
return g_string_free (out, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
g_unix_socket_address_init (GUnixSocketAddress *address)
|
||||
{
|
||||
|
@ -235,6 +235,55 @@ test_socket_address (void)
|
||||
g_object_unref (saddr);
|
||||
}
|
||||
|
||||
static void
|
||||
test_socket_address_to_string (void)
|
||||
{
|
||||
GSocketAddress *sa = NULL;
|
||||
GInetAddress *ia = NULL;
|
||||
gchar *str = NULL;
|
||||
|
||||
/* IPv4. */
|
||||
ia = g_inet_address_new_from_string ("123.1.123.1");
|
||||
sa = g_inet_socket_address_new (ia, 80);
|
||||
str = g_socket_connectable_to_string (G_SOCKET_CONNECTABLE (sa));
|
||||
g_assert_cmpstr (str, ==, "123.1.123.1:80");
|
||||
g_free (str);
|
||||
g_object_unref (sa);
|
||||
g_object_unref (ia);
|
||||
|
||||
/* IPv6. */
|
||||
ia = g_inet_address_new_from_string ("::80");
|
||||
sa = g_inet_socket_address_new (ia, 80);
|
||||
str = g_socket_connectable_to_string (G_SOCKET_CONNECTABLE (sa));
|
||||
g_assert_cmpstr (str, ==, "[::80]:80");
|
||||
g_free (str);
|
||||
g_object_unref (sa);
|
||||
g_object_unref (ia);
|
||||
|
||||
/* IPv6 without port. */
|
||||
ia = g_inet_address_new_from_string ("::80");
|
||||
sa = g_inet_socket_address_new (ia, 0);
|
||||
str = g_socket_connectable_to_string (G_SOCKET_CONNECTABLE (sa));
|
||||
g_assert_cmpstr (str, ==, "::80");
|
||||
g_free (str);
|
||||
g_object_unref (sa);
|
||||
g_object_unref (ia);
|
||||
|
||||
/* IPv6 with scope. */
|
||||
ia = g_inet_address_new_from_string ("::1");
|
||||
sa = G_SOCKET_ADDRESS (g_object_new (G_TYPE_INET_SOCKET_ADDRESS,
|
||||
"address", ia,
|
||||
"port", 123,
|
||||
"flowinfo", 10,
|
||||
"scope-id", 25,
|
||||
NULL));
|
||||
str = g_socket_connectable_to_string (G_SOCKET_CONNECTABLE (sa));
|
||||
g_assert_cmpstr (str, ==, "[::1%25]:123");
|
||||
g_free (str);
|
||||
g_object_unref (sa);
|
||||
g_object_unref (ia);
|
||||
}
|
||||
|
||||
static void
|
||||
test_mask_parse (void)
|
||||
{
|
||||
@ -368,6 +417,7 @@ main (int argc, char *argv[])
|
||||
g_test_add_func ("/inet-address/bytes", test_bytes);
|
||||
g_test_add_func ("/inet-address/property", test_property);
|
||||
g_test_add_func ("/socket-address/basic", test_socket_address);
|
||||
g_test_add_func ("/socket-address/to-string", test_socket_address_to_string);
|
||||
g_test_add_func ("/address-mask/parse", test_mask_parse);
|
||||
g_test_add_func ("/address-mask/property", test_mask_property);
|
||||
g_test_add_func ("/address-mask/equal", test_mask_equal);
|
||||
|
@ -477,6 +477,43 @@ test_loopback_async (void)
|
||||
g_object_unref (addr);
|
||||
}
|
||||
|
||||
static void
|
||||
test_to_string (void)
|
||||
{
|
||||
GSocketConnectable *addr = NULL;
|
||||
gchar *str = NULL;
|
||||
GError *error = NULL;
|
||||
|
||||
/* Without port. */
|
||||
addr = g_network_address_new ("some-hostname", 0);
|
||||
str = g_socket_connectable_to_string (addr);
|
||||
g_assert_cmpstr (str, ==, "some-hostname");
|
||||
g_free (str);
|
||||
g_object_unref (addr);
|
||||
|
||||
/* With port. */
|
||||
addr = g_network_address_new ("some-hostname", 123);
|
||||
str = g_socket_connectable_to_string (addr);
|
||||
g_assert_cmpstr (str, ==, "some-hostname:123");
|
||||
g_free (str);
|
||||
g_object_unref (addr);
|
||||
|
||||
/* With scheme and port. */
|
||||
addr = g_network_address_parse_uri ("http://some-hostname:123", 80, &error);
|
||||
g_assert_no_error (error);
|
||||
str = g_socket_connectable_to_string (addr);
|
||||
g_assert_cmpstr (str, ==, "http:some-hostname:123");
|
||||
g_free (str);
|
||||
g_object_unref (addr);
|
||||
|
||||
/* Loopback. */
|
||||
addr = g_network_address_new ("localhost", 456);
|
||||
str = g_socket_connectable_to_string (addr);
|
||||
g_assert_cmpstr (str, ==, "localhost:456");
|
||||
g_free (str);
|
||||
g_object_unref (addr);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
@ -520,6 +557,7 @@ main (int argc, char *argv[])
|
||||
g_test_add_func ("/network-address/loopback/basic", test_loopback_basic);
|
||||
g_test_add_func ("/network-address/loopback/sync", test_loopback_sync);
|
||||
g_test_add_func ("/network-address/loopback/async", test_loopback_async);
|
||||
g_test_add_func ("/network-address/to-string", test_to_string);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
|
@ -67,6 +67,45 @@ test_unix_socket_address_construct (void)
|
||||
g_object_unref (a);
|
||||
}
|
||||
|
||||
static void
|
||||
test_unix_socket_address_to_string (void)
|
||||
{
|
||||
GSocketAddress *addr = NULL;
|
||||
gchar *str = NULL;
|
||||
|
||||
/* ADDRESS_PATH. */
|
||||
addr = g_unix_socket_address_new_with_type ("/some/path", -1,
|
||||
G_UNIX_SOCKET_ADDRESS_PATH);
|
||||
str = g_socket_connectable_to_string (G_SOCKET_CONNECTABLE (addr));
|
||||
g_assert_cmpstr (str, ==, "/some/path");
|
||||
g_free (str);
|
||||
g_object_unref (addr);
|
||||
|
||||
/* ADDRESS_ANONYMOUS. */
|
||||
addr = g_unix_socket_address_new_with_type ("", 0,
|
||||
G_UNIX_SOCKET_ADDRESS_ANONYMOUS);
|
||||
str = g_socket_connectable_to_string (G_SOCKET_CONNECTABLE (addr));
|
||||
g_assert_cmpstr (str, ==, "anonymous");
|
||||
g_free (str);
|
||||
g_object_unref (addr);
|
||||
|
||||
/* ADDRESS_ABSTRACT. */
|
||||
addr = g_unix_socket_address_new_with_type ("abstract-path\0✋", 17,
|
||||
G_UNIX_SOCKET_ADDRESS_ABSTRACT);
|
||||
str = g_socket_connectable_to_string (G_SOCKET_CONNECTABLE (addr));
|
||||
g_assert_cmpstr (str, ==, "abstract-path\\x00\\xe2\\x9c\\x8b");
|
||||
g_free (str);
|
||||
g_object_unref (addr);
|
||||
|
||||
/* ADDRESS_ABSTRACT_PADDED. */
|
||||
addr = g_unix_socket_address_new_with_type ("abstract-path\0✋", 17,
|
||||
G_UNIX_SOCKET_ADDRESS_ABSTRACT_PADDED);
|
||||
str = g_socket_connectable_to_string (G_SOCKET_CONNECTABLE (addr));
|
||||
g_assert_cmpstr (str, ==, "abstract-path\\x00\\xe2\\x9c\\x8b");
|
||||
g_free (str);
|
||||
g_object_unref (addr);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char **argv)
|
||||
@ -74,6 +113,7 @@ main (int argc,
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
|
||||
g_test_add_func ("/socket/address/unix/construct", test_unix_socket_address_construct);
|
||||
g_test_add_func ("/socket/address/unix/to-string", test_unix_socket_address_to_string);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user