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...)
This commit is contained in:
Dan Winship 2011-09-03 19:14:16 -04:00
parent 0d63793129
commit af2a905e54

View File

@ -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: