From af2a905e5480bc7eb82e7a43ef7fead7b3b90dd7 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Sat, 3 Sep 2011 19:14:16 -0400 Subject: [PATCH] gsocket: fix g_socket_details_from_fd() on Solaris On Solaris, getsockname() on an unconnected socket gives an addrlen of 0 and doesn't set the sockaddr. So use the SO_DOMAIN sockopt to find the socket family in that case. (SO_DOMAIN doesn't exist everywhere, so we can't use it unconditionally. Also, we have to only use it if getsockname() fails, since SO_DOMAIN returns a bogus value for accept()ed sockets on both Linux and Solaris...) --- gio/gsocket.c | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/gio/gsocket.c b/gio/gsocket.c index 2ee0b5c..9d58c41 100644 --- a/gio/gsocket.c +++ b/gio/gsocket.c @@ -309,7 +309,7 @@ g_socket_details_from_fd (GSocket *socket) gint fd; guint addrlen; guint optlen; - int value; + int value, family; int errsv; #ifdef G_OS_WIN32 /* See bug #611756 */ @@ -370,9 +370,31 @@ g_socket_details_from_fd (GSocket *socket) goto err; } - g_assert (G_STRUCT_OFFSET (struct sockaddr, sa_family) + - sizeof address.ss_family <= addrlen); - switch (address.ss_family) + if (addrlen > 0) + { + g_assert (G_STRUCT_OFFSET (struct sockaddr, sa_family) + + sizeof address.ss_family <= addrlen); + family = address.ss_family; + } + else + { + /* On Solaris, this happens if the socket is not yet connected. + * But we can use SO_DOMAIN as a workaround there. + */ +#ifdef SO_DOMAIN + optlen = sizeof family; + if (getsockopt (fd, SOL_SOCKET, SO_DOMAIN, (void *)&family, &optlen) != 0) + { + errsv = get_socket_errno (); + goto err; + } +#else + errsv = ENOTSUP; + goto err; +#endif + } + + switch (family) { case G_SOCKET_FAMILY_IPV4: case G_SOCKET_FAMILY_IPV6: -- 2.7.4