GNOME Bugzilla – Bug 732317
Support GSocketConnectable for loopback addresses
Last modified: 2014-11-29 19:23:02 UTC
Currently, to connect to a local service using IPv4 or IPv6 (where you don’t know whether the service is running on one or the other) on a loopback connection, you need to manually create several GInetSocketAddresses: GInetAddress *ipv4_address = g_inet_address_new_loopback (G_SOCKET_FAMILY_IPV4); GInetSocketAddress *ipv4_s_address = g_inet_socket_address_new (ipv4_address, 1234); /* same for IPv6, then somehow try and connect to both and choose the one which works */ It would be more useful if we could have a GSocketConnectable which would automatically enumerate all possible loopback addresses (i.e. both IPv4 and IPv6) on the given port, so that we can use g_socket_client_connect() to magically enumerate and try the different addresses. Using a GNetworkAddress doesn’t work (and I’m not sure it _can_ work): g_network_address_new ("localhost", 1234); gives a GSocketConnectable which only enumerates 127.0.0.1, and not ::1 as well. This is because /etc/hosts lists localhost and localhost6 separately. (Why is that?) So either we could somehow change GNetworkAddress to have some way of resolving to 127.0.0.1 *and* ::1; or we could add a new GSocketConnectable implementation which enumerates loopback addresses for a specified port. e.g.: GLoopbackAddress extends GObject, implements GSocketConnectable GSocketConnectable *g_loopback_address_new (guint16 port); Which option would make more sense?
(In reply to comment #0) > Using a GNetworkAddress doesn’t work (and I’m not sure it _can_ work): > > g_network_address_new ("localhost", 1234); > > gives a GSocketConnectable which only enumerates 127.0.0.1, and not ::1 as > well. This is because /etc/hosts lists localhost and localhost6 separately. > (Why is that?) That's distro-specific to some extent, but I think it's because in the past, some code looked up 'localhost' and couldn't deal with getting back an IPv6 address. > So either we could somehow change GNetworkAddress to have some way of resolving > to 127.0.0.1 *and* ::1; or we could add a new GSocketConnectable implementation > which enumerates loopback addresses for a specified port. e.g.: > > GLoopbackAddress extends GObject, implements GSocketConnectable > GSocketConnectable *g_loopback_address_new (guint16 port); > > Which option would make more sense? I don't think we should special-case 'g_network_address_new("localhost", port)', but we could add g_network_address_new_localhost() (or _new_loopback()) that returned a GNetworkAddress with hostname='localhost', but always had both addresses. (So basically like your second idea, except without the effort of creating a new subclass.)
Created attachment 289404 [details] [review] gnetworkaddress: Add g_network_address_new_loopback() constructor This is a convenience method for creating a GNetworkAddress which is guaranteed to return IPv4 and IPv6 loopback addresses. The host cannot guarantee to resolve ‘localhost’ to both types of address, so programs which wish to connect to a local service over IPv4 or IPv6 must currently manually create an IPv4 and another IPv6 socket, and detect which of the two are working. This new API allows the existing GSocketConnectable machinery to be used to automate that. Unit tests are included.
Created attachment 291318 [details] [review] gnetworkaddress: Add g_network_address_new_loopback() constructor I was imagining something a little simpler than that. Does this work for you?
(In reply to comment #3) > Created an attachment (id=291318) [details] [review] > gnetworkaddress: Add g_network_address_new_loopback() constructor > > I was imagining something a little simpler than that. Does this work > for you? That looks a lot simpler, yes. Looks good to me. :-)
Attachment 291318 [details] pushed as 64f9bf9 - gnetworkaddress: Add g_network_address_new_loopback() constructor