mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-01-12 15:36:17 +01:00
gsocket: add getsockopt/setsockopt wrappers
Add g_socket_get_option() and g_socket_set_option(), wrapping getsockopt/setsockopt for the case of integer-valued options. Update code to use these instead of the underlying calls. https://bugzilla.gnome.org/show_bug.cgi?id=623187
This commit is contained in:
parent
b377e69685
commit
211ed1775d
36
configure.ac
36
configure.ac
@ -1065,25 +1065,25 @@ fi
|
||||
|
||||
AC_CHECK_FUNCS(getprotobyname_r endservent if_nametoindex)
|
||||
|
||||
# <wspiapi.h> in the Windows SDK and in mingw-w64 has wrappers for
|
||||
# inline workarounds for getaddrinfo, getnameinfo and freeaddrinfo if
|
||||
# they aren't present at run-time (on Windows 2000).
|
||||
AC_CHECK_HEADER([wspiapi.h], [WSPIAPI_INCLUDE="\#include <wspiapi.h>"])
|
||||
AC_SUBST(WSPIAPI_INCLUDE)
|
||||
AS_IF([test $glib_native_win32 = yes], [
|
||||
# <wspiapi.h> in the Windows SDK and in mingw-w64 has wrappers for
|
||||
# inline workarounds for getaddrinfo, getnameinfo and freeaddrinfo if
|
||||
# they aren't present at run-time (on Windows 2000).
|
||||
AC_CHECK_HEADER([wspiapi.h], [WSPIAPI_INCLUDE="#include <wspiapi.h>"])
|
||||
AC_SUBST(WSPIAPI_INCLUDE)
|
||||
], [
|
||||
AC_MSG_CHECKING([if arpa/nameser_compat.h is needed])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include <arpa/nameser.h>],
|
||||
[int qclass = C_IN;])],
|
||||
[AC_MSG_RESULT([no])],
|
||||
[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include <arpa/nameser.h>
|
||||
#include <arpa/nameser_compat.h>],
|
||||
[int qclass = C_IN;])],
|
||||
[AC_MSG_RESULT([yes])
|
||||
NAMESER_COMPAT_INCLUDE="\#include <arpa/nameser_compat.h>"],
|
||||
[AC_MSG_ERROR([could not compile test program either way])])])
|
||||
AC_SUBST(NAMESER_COMPAT_INCLUDE)
|
||||
|
||||
AC_MSG_CHECKING([if arpa/nameser_compat.h is needed])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include <arpa/nameser.h>],
|
||||
[int qclass = C_IN;])],
|
||||
[AC_MSG_RESULT([no])],
|
||||
[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include <arpa/nameser.h>
|
||||
#include <arpa/nameser_compat.h>],
|
||||
[int qclass = C_IN;])],
|
||||
[AC_MSG_RESULT([yes])
|
||||
NAMESER_COMPAT_INCLUDE="\#include <arpa/nameser_compat.h>"],
|
||||
[AC_MSG_ERROR([could not compile test program either way])])])
|
||||
AC_SUBST(NAMESER_COMPAT_INCLUDE)
|
||||
|
||||
AS_IF([test $glib_native_win32 = no], [
|
||||
# We can't just use AC_CHECK_FUNC/AC_CHECK_LIB here. Bug 586150
|
||||
NETWORK_LIBS=""
|
||||
AC_MSG_CHECKING([for res_query])
|
||||
|
@ -1900,6 +1900,8 @@ g_socket_set_ttl
|
||||
g_socket_get_ttl
|
||||
g_socket_get_broadcast
|
||||
g_socket_set_broadcast
|
||||
g_socket_get_option
|
||||
g_socket_set_option
|
||||
g_socket_get_family
|
||||
g_socket_get_fd
|
||||
g_socket_get_local_address
|
||||
|
@ -1001,6 +1001,7 @@ g_socket_get_listen_backlog
|
||||
g_socket_get_local_address
|
||||
g_socket_get_multicast_loopback
|
||||
g_socket_get_multicast_ttl
|
||||
g_socket_get_option
|
||||
g_socket_get_protocol
|
||||
g_socket_get_remote_address
|
||||
g_socket_get_socket_type
|
||||
@ -1027,6 +1028,7 @@ g_socket_set_keepalive
|
||||
g_socket_set_listen_backlog
|
||||
g_socket_set_multicast_loopback
|
||||
g_socket_set_multicast_ttl
|
||||
g_socket_set_option
|
||||
g_socket_speaks_ipv4
|
||||
g_socket_get_credentials
|
||||
g_socket_control_message_get_type
|
||||
|
@ -83,7 +83,7 @@ g_network_monitor_netlink_initable_init (GInitable *initable,
|
||||
GError **error)
|
||||
{
|
||||
GNetworkMonitorNetlink *nl = G_NETWORK_MONITOR_NETLINK (initable);
|
||||
gint sockfd, val;
|
||||
gint sockfd;
|
||||
struct sockaddr_nl snl;
|
||||
|
||||
/* We create the socket the old-school way because sockaddr_netlink
|
||||
@ -112,17 +112,6 @@ g_network_monitor_netlink_initable_init (GInitable *initable,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
val = 1;
|
||||
if (setsockopt (sockfd, SOL_SOCKET, SO_PASSCRED, &val, sizeof (val)) != 0)
|
||||
{
|
||||
int errsv = errno;
|
||||
g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
|
||||
_("Could not create network monitor: %s"),
|
||||
g_strerror (errno));
|
||||
close (sockfd);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
nl->priv->sock = g_socket_new_from_fd (sockfd, error);
|
||||
if (error)
|
||||
{
|
||||
@ -131,6 +120,16 @@ g_network_monitor_netlink_initable_init (GInitable *initable,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!g_socket_set_option (nl->priv->sock, SOL_SOCKET, SO_PASSCRED,
|
||||
TRUE, NULL))
|
||||
{
|
||||
int errsv = errno;
|
||||
g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
|
||||
_("Could not create network monitor: %s"),
|
||||
g_strerror (errno));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Request the current state */
|
||||
if (!request_dump (nl, error))
|
||||
return FALSE;
|
||||
|
356
gio/gsocket.c
356
gio/gsocket.c
@ -344,19 +344,11 @@ g_socket_details_from_fd (GSocket *socket)
|
||||
struct sockaddr_storage address;
|
||||
gint fd;
|
||||
guint addrlen;
|
||||
guint optlen;
|
||||
int value, family;
|
||||
int errsv;
|
||||
#ifdef G_OS_WIN32
|
||||
/* See bug #611756 */
|
||||
BOOL bool_val = FALSE;
|
||||
#else
|
||||
int bool_val;
|
||||
#endif
|
||||
|
||||
fd = socket->priv->fd;
|
||||
optlen = sizeof value;
|
||||
if (getsockopt (fd, SOL_SOCKET, SO_TYPE, (void *)&value, &optlen) != 0)
|
||||
if (!g_socket_get_option (socket, SOL_SOCKET, SO_TYPE, &value, NULL))
|
||||
{
|
||||
errsv = get_socket_errno ();
|
||||
|
||||
@ -380,7 +372,6 @@ g_socket_details_from_fd (GSocket *socket)
|
||||
goto err;
|
||||
}
|
||||
|
||||
g_assert (optlen == sizeof value);
|
||||
switch (value)
|
||||
{
|
||||
case SOCK_STREAM:
|
||||
@ -419,8 +410,7 @@ g_socket_details_from_fd (GSocket *socket)
|
||||
* 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)
|
||||
if (!g_socket_get_option (socket, SOL_SOCKET, SO_DOMAIN, &family, NULL))
|
||||
{
|
||||
errsv = get_socket_errno ();
|
||||
goto err;
|
||||
@ -473,19 +463,9 @@ g_socket_details_from_fd (GSocket *socket)
|
||||
socket->priv->connected = TRUE;
|
||||
}
|
||||
|
||||
optlen = sizeof bool_val;
|
||||
if (getsockopt (fd, SOL_SOCKET, SO_KEEPALIVE,
|
||||
(void *)&bool_val, &optlen) == 0)
|
||||
if (g_socket_get_option (socket, SOL_SOCKET, SO_KEEPALIVE, &value, NULL))
|
||||
{
|
||||
#ifndef G_OS_WIN32
|
||||
/* Experimentation indicates that the SO_KEEPALIVE value is
|
||||
* actually a char on Windows, even if documentation claims it
|
||||
* to be a BOOL which is a typedef for int. So this g_assert()
|
||||
* fails. See bug #611756.
|
||||
*/
|
||||
g_assert (optlen == sizeof bool_val);
|
||||
#endif
|
||||
socket->priv->keepalive = !!bool_val;
|
||||
socket->priv->keepalive = !!value;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1154,7 +1134,7 @@ void
|
||||
g_socket_set_keepalive (GSocket *socket,
|
||||
gboolean keepalive)
|
||||
{
|
||||
int value;
|
||||
GError *error = NULL;
|
||||
|
||||
g_return_if_fail (G_IS_SOCKET (socket));
|
||||
|
||||
@ -1162,12 +1142,11 @@ g_socket_set_keepalive (GSocket *socket,
|
||||
if (socket->priv->keepalive == keepalive)
|
||||
return;
|
||||
|
||||
value = (gint) keepalive;
|
||||
if (setsockopt (socket->priv->fd, SOL_SOCKET, SO_KEEPALIVE,
|
||||
(gpointer) &value, sizeof (value)) < 0)
|
||||
if (!g_socket_set_option (socket, SOL_SOCKET, SO_KEEPALIVE,
|
||||
keepalive, &error))
|
||||
{
|
||||
int errsv = get_socket_errno ();
|
||||
g_warning ("error setting keepalive: %s", socket_strerror (errsv));
|
||||
g_warning ("error setting keepalive: %s", error->message);
|
||||
g_error_free (error);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1316,34 +1295,29 @@ g_socket_set_timeout (GSocket *socket,
|
||||
guint
|
||||
g_socket_get_ttl (GSocket *socket)
|
||||
{
|
||||
int result;
|
||||
guint value, optlen;
|
||||
GError *error = NULL;
|
||||
gint value;
|
||||
|
||||
g_return_val_if_fail (G_IS_SOCKET (socket), FALSE);
|
||||
g_return_val_if_fail (G_IS_SOCKET (socket), 0);
|
||||
|
||||
if (socket->priv->family == G_SOCKET_FAMILY_IPV4)
|
||||
{
|
||||
guchar optval;
|
||||
|
||||
optlen = sizeof (optval);
|
||||
result = getsockopt (socket->priv->fd, IPPROTO_IP, IP_TTL,
|
||||
&optval, &optlen);
|
||||
value = optval;
|
||||
g_socket_get_option (socket, IPPROTO_IP, IP_TTL,
|
||||
&value, &error);
|
||||
}
|
||||
else if (socket->priv->family == G_SOCKET_FAMILY_IPV6)
|
||||
{
|
||||
optlen = sizeof (value);
|
||||
result = getsockopt (socket->priv->fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
|
||||
&value, &optlen);
|
||||
g_socket_get_option (socket, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
|
||||
&value, &error);
|
||||
}
|
||||
else
|
||||
g_return_val_if_reached (FALSE);
|
||||
g_return_val_if_reached (0);
|
||||
|
||||
if (result < 0)
|
||||
if (error)
|
||||
{
|
||||
int errsv = get_socket_errno ();
|
||||
g_warning ("error getting unicast ttl: %s", socket_strerror (errsv));
|
||||
return FALSE;
|
||||
g_warning ("error getting unicast ttl: %s", error->message);
|
||||
g_error_free (error);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return value;
|
||||
@ -1363,29 +1337,27 @@ void
|
||||
g_socket_set_ttl (GSocket *socket,
|
||||
guint ttl)
|
||||
{
|
||||
int result;
|
||||
GError *error = NULL;
|
||||
|
||||
g_return_if_fail (G_IS_SOCKET (socket));
|
||||
|
||||
if (socket->priv->family == G_SOCKET_FAMILY_IPV4)
|
||||
{
|
||||
guchar optval = (guchar)ttl;
|
||||
|
||||
result = setsockopt (socket->priv->fd, IPPROTO_IP, IP_TTL,
|
||||
&optval, sizeof (optval));
|
||||
g_socket_set_option (socket, IPPROTO_IP, IP_TTL,
|
||||
ttl, &error);
|
||||
}
|
||||
else if (socket->priv->family == G_SOCKET_FAMILY_IPV6)
|
||||
{
|
||||
result = setsockopt (socket->priv->fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
|
||||
&ttl, sizeof (ttl));
|
||||
g_socket_set_option (socket, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
|
||||
ttl, &error);
|
||||
}
|
||||
else
|
||||
g_return_if_reached ();
|
||||
|
||||
if (result < 0)
|
||||
if (error)
|
||||
{
|
||||
int errsv = get_socket_errno ();
|
||||
g_warning ("error setting unicast ttl: %s", socket_strerror (errsv));
|
||||
g_warning ("error setting unicast ttl: %s", error->message);
|
||||
g_error_free (error);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1407,19 +1379,16 @@ g_socket_set_ttl (GSocket *socket,
|
||||
gboolean
|
||||
g_socket_get_broadcast (GSocket *socket)
|
||||
{
|
||||
int result;
|
||||
guint value = 0, optlen;
|
||||
GError *error = NULL;
|
||||
gint value;
|
||||
|
||||
g_return_val_if_fail (G_IS_SOCKET (socket), FALSE);
|
||||
|
||||
optlen = sizeof (guchar);
|
||||
result = getsockopt (socket->priv->fd, SOL_SOCKET, SO_BROADCAST,
|
||||
&value, &optlen);
|
||||
|
||||
if (result < 0)
|
||||
if (!g_socket_get_option (socket, SOL_SOCKET, SO_BROADCAST,
|
||||
&value, &error))
|
||||
{
|
||||
int errsv = get_socket_errno ();
|
||||
g_warning ("error getting broadcast: %s", socket_strerror (errsv));
|
||||
g_warning ("error getting broadcast: %s", error->message);
|
||||
g_error_free (error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -1441,21 +1410,17 @@ void
|
||||
g_socket_set_broadcast (GSocket *socket,
|
||||
gboolean broadcast)
|
||||
{
|
||||
int result;
|
||||
gint value;
|
||||
GError *error = NULL;
|
||||
|
||||
g_return_if_fail (G_IS_SOCKET (socket));
|
||||
|
||||
broadcast = !!broadcast;
|
||||
value = (guchar)broadcast;
|
||||
|
||||
result = setsockopt (socket->priv->fd, SOL_SOCKET, SO_BROADCAST,
|
||||
&value, sizeof (value));
|
||||
|
||||
if (result < 0)
|
||||
if (!g_socket_set_option (socket, SOL_SOCKET, SO_BROADCAST,
|
||||
broadcast, &error))
|
||||
{
|
||||
int errsv = get_socket_errno ();
|
||||
g_warning ("error setting broadcast: %s", socket_strerror (errsv));
|
||||
g_warning ("error setting broadcast: %s", error->message);
|
||||
g_error_free (error);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1477,30 +1442,28 @@ g_socket_set_broadcast (GSocket *socket,
|
||||
gboolean
|
||||
g_socket_get_multicast_loopback (GSocket *socket)
|
||||
{
|
||||
int result;
|
||||
guint value = 0, optlen;
|
||||
GError *error = NULL;
|
||||
gint value;
|
||||
|
||||
g_return_val_if_fail (G_IS_SOCKET (socket), FALSE);
|
||||
|
||||
if (socket->priv->family == G_SOCKET_FAMILY_IPV4)
|
||||
{
|
||||
optlen = sizeof (guchar);
|
||||
result = getsockopt (socket->priv->fd, IPPROTO_IP, IP_MULTICAST_LOOP,
|
||||
&value, &optlen);
|
||||
g_socket_get_option (socket, IPPROTO_IP, IP_MULTICAST_LOOP,
|
||||
&value, &error);
|
||||
}
|
||||
else if (socket->priv->family == G_SOCKET_FAMILY_IPV6)
|
||||
{
|
||||
optlen = sizeof (guint);
|
||||
result = getsockopt (socket->priv->fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
|
||||
&value, &optlen);
|
||||
g_socket_get_option (socket, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
|
||||
&value, &error);
|
||||
}
|
||||
else
|
||||
g_return_val_if_reached (FALSE);
|
||||
|
||||
if (result < 0)
|
||||
if (error)
|
||||
{
|
||||
int errsv = get_socket_errno ();
|
||||
g_warning ("error getting multicast loopback: %s", socket_strerror (errsv));
|
||||
g_warning ("error getting multicast loopback: %s", error->message);
|
||||
g_error_free (error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -1523,7 +1486,7 @@ void
|
||||
g_socket_set_multicast_loopback (GSocket *socket,
|
||||
gboolean loopback)
|
||||
{
|
||||
int result;
|
||||
GError *error = NULL;
|
||||
|
||||
g_return_if_fail (G_IS_SOCKET (socket));
|
||||
|
||||
@ -1531,25 +1494,21 @@ g_socket_set_multicast_loopback (GSocket *socket,
|
||||
|
||||
if (socket->priv->family == G_SOCKET_FAMILY_IPV4)
|
||||
{
|
||||
guchar value = (guchar)loopback;
|
||||
|
||||
result = setsockopt (socket->priv->fd, IPPROTO_IP, IP_MULTICAST_LOOP,
|
||||
&value, sizeof (value));
|
||||
g_socket_set_option (socket, IPPROTO_IP, IP_MULTICAST_LOOP,
|
||||
loopback, &error);
|
||||
}
|
||||
else if (socket->priv->family == G_SOCKET_FAMILY_IPV6)
|
||||
{
|
||||
guint value = (guint)loopback;
|
||||
|
||||
result = setsockopt (socket->priv->fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
|
||||
&value, sizeof (value));
|
||||
g_socket_set_option (socket, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
|
||||
loopback, &error);
|
||||
}
|
||||
else
|
||||
g_return_if_reached ();
|
||||
|
||||
if (result < 0)
|
||||
if (error)
|
||||
{
|
||||
int errsv = get_socket_errno ();
|
||||
g_warning ("error setting multicast loopback: %s", socket_strerror (errsv));
|
||||
g_warning ("error setting multicast loopback: %s", error->message);
|
||||
g_error_free (error);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1570,33 +1529,28 @@ g_socket_set_multicast_loopback (GSocket *socket,
|
||||
guint
|
||||
g_socket_get_multicast_ttl (GSocket *socket)
|
||||
{
|
||||
int result;
|
||||
guint value, optlen;
|
||||
GError *error = NULL;
|
||||
gint value;
|
||||
|
||||
g_return_val_if_fail (G_IS_SOCKET (socket), FALSE);
|
||||
|
||||
if (socket->priv->family == G_SOCKET_FAMILY_IPV4)
|
||||
{
|
||||
guchar optval;
|
||||
|
||||
optlen = sizeof (optval);
|
||||
result = getsockopt (socket->priv->fd, IPPROTO_IP, IP_MULTICAST_TTL,
|
||||
&optval, &optlen);
|
||||
value = optval;
|
||||
g_socket_get_option (socket, IPPROTO_IP, IP_MULTICAST_TTL,
|
||||
&value, &error);
|
||||
}
|
||||
else if (socket->priv->family == G_SOCKET_FAMILY_IPV6)
|
||||
{
|
||||
optlen = sizeof (value);
|
||||
result = getsockopt (socket->priv->fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
|
||||
&value, &optlen);
|
||||
g_socket_get_option (socket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
|
||||
&value, &error);
|
||||
}
|
||||
else
|
||||
g_return_val_if_reached (FALSE);
|
||||
|
||||
if (result < 0)
|
||||
if (error)
|
||||
{
|
||||
int errsv = get_socket_errno ();
|
||||
g_warning ("error getting multicast ttl: %s", socket_strerror (errsv));
|
||||
g_warning ("error getting multicast ttl: %s", error->message);
|
||||
g_error_free (error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -1618,29 +1572,27 @@ void
|
||||
g_socket_set_multicast_ttl (GSocket *socket,
|
||||
guint ttl)
|
||||
{
|
||||
int result;
|
||||
GError *error = NULL;
|
||||
|
||||
g_return_if_fail (G_IS_SOCKET (socket));
|
||||
|
||||
if (socket->priv->family == G_SOCKET_FAMILY_IPV4)
|
||||
{
|
||||
guchar optval = (guchar)ttl;
|
||||
|
||||
result = setsockopt (socket->priv->fd, IPPROTO_IP, IP_MULTICAST_TTL,
|
||||
&optval, sizeof (optval));
|
||||
g_socket_set_option (socket, IPPROTO_IP, IP_MULTICAST_TTL,
|
||||
ttl, &error);
|
||||
}
|
||||
else if (socket->priv->family == G_SOCKET_FAMILY_IPV6)
|
||||
{
|
||||
result = setsockopt (socket->priv->fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
|
||||
&ttl, sizeof (ttl));
|
||||
g_socket_set_option (socket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
|
||||
ttl, &error);
|
||||
}
|
||||
else
|
||||
g_return_if_reached ();
|
||||
|
||||
if (result < 0)
|
||||
if (error)
|
||||
{
|
||||
int errsv = get_socket_errno ();
|
||||
g_warning ("error setting multicast ttl: %s", socket_strerror (errsv));
|
||||
g_warning ("error setting multicast ttl: %s", error->message);
|
||||
g_error_free (error);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1910,13 +1862,11 @@ g_socket_bind (GSocket *socket,
|
||||
It always allows the unix variant of SO_REUSEADDR anyway */
|
||||
#ifndef G_OS_WIN32
|
||||
{
|
||||
int value;
|
||||
|
||||
value = (int) !!reuse_address;
|
||||
reuse_address = !!reuse_address;
|
||||
/* Ignore errors here, the only likely error is "not supported", and
|
||||
this is a "best effort" thing mainly */
|
||||
setsockopt (socket->priv->fd, SOL_SOCKET, SO_REUSEADDR,
|
||||
(gpointer) &value, sizeof (value));
|
||||
g_socket_set_option (socket, SOL_SOCKET, SO_REUSEADDR,
|
||||
reuse_address, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -2121,12 +2071,11 @@ g_socket_speaks_ipv4 (GSocket *socket)
|
||||
case G_SOCKET_FAMILY_IPV6:
|
||||
#if defined (IPPROTO_IPV6) && defined (IPV6_V6ONLY)
|
||||
{
|
||||
guint sizeof_int = sizeof (int);
|
||||
gint v6_only;
|
||||
|
||||
if (getsockopt (socket->priv->fd,
|
||||
IPPROTO_IPV6, IPV6_V6ONLY,
|
||||
&v6_only, &sizeof_int) != 0)
|
||||
if (!g_socket_get_option (socket,
|
||||
IPPROTO_IPV6, IPV6_V6ONLY,
|
||||
&v6_only, NULL))
|
||||
return FALSE;
|
||||
|
||||
return !v6_only;
|
||||
@ -2364,7 +2313,6 @@ gboolean
|
||||
g_socket_check_connect_result (GSocket *socket,
|
||||
GError **error)
|
||||
{
|
||||
guint optlen;
|
||||
int value;
|
||||
|
||||
g_return_val_if_fail (G_IS_SOCKET (socket), FALSE);
|
||||
@ -2372,13 +2320,9 @@ g_socket_check_connect_result (GSocket *socket,
|
||||
if (!check_socket (socket, error))
|
||||
return FALSE;
|
||||
|
||||
optlen = sizeof (value);
|
||||
if (getsockopt (socket->priv->fd, SOL_SOCKET, SO_ERROR, (void *)&value, &optlen) != 0)
|
||||
if (!g_socket_get_option (socket, SOL_SOCKET, SO_ERROR, &value, error))
|
||||
{
|
||||
int errsv = get_socket_errno ();
|
||||
|
||||
g_set_error (error, G_IO_ERROR, socket_io_error_from_errno (errsv),
|
||||
_("Unable to get pending error: %s"), socket_strerror (errsv));
|
||||
g_prefix_error (error, _("Unable to get pending error: "));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -4425,3 +4369,139 @@ g_socket_get_credentials (GSocket *socket,
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_socket_get_option:
|
||||
* @socket: a #GSocket
|
||||
* @level: the "API level" of the option (eg, <literal>SOL_SOCKET</literal>)
|
||||
* @optname: the "name" of the option (eg, <literal>SO_BROADCAST</literal>)
|
||||
* @value: (out): return location for the option value
|
||||
* @error: #GError for error reporting, or %NULL to ignore.
|
||||
*
|
||||
* Gets the value of an integer-valued option on @socket, as with
|
||||
* <literal>getsockopt ()</literal>. (If you need to fetch a
|
||||
* non-integer-valued option, you will need to call
|
||||
* <literal>getsockopt ()</literal> directly.)
|
||||
*
|
||||
* The <link linkend="gio-gnetworking.h"><literal><gio/gnetworking.h></literal></link>
|
||||
* header pulls in system headers that will define most of the
|
||||
* standard/portable socket options. For unusual socket protocols or
|
||||
* platform-dependent options, you may need to include additional
|
||||
* headers.
|
||||
*
|
||||
* Note that even for socket options that are a single byte in size,
|
||||
* @value is still a pointer to a #gint variable, not a #guchar;
|
||||
* g_socket_get_option() will handle the conversion internally.
|
||||
*
|
||||
* Returns: success or failure. On failure, @error will be set, and
|
||||
* the system error value (<literal>errno</literal> or
|
||||
* <literal>WSAGetLastError ()</literal>) will still be set to the
|
||||
* result of the <literal>getsockopt ()</literal> call.
|
||||
*
|
||||
* Since: 2.36
|
||||
*/
|
||||
gboolean
|
||||
g_socket_get_option (GSocket *socket,
|
||||
gint level,
|
||||
gint optname,
|
||||
gint *value,
|
||||
GError **error)
|
||||
{
|
||||
guint size;
|
||||
|
||||
g_return_val_if_fail (G_IS_SOCKET (socket), FALSE);
|
||||
|
||||
*value = 0;
|
||||
size = sizeof (gint);
|
||||
if (getsockopt (socket->priv->fd, level, optname, value, &size) != 0)
|
||||
{
|
||||
int errsv = get_socket_errno ();
|
||||
|
||||
g_set_error_literal (error,
|
||||
G_IO_ERROR,
|
||||
socket_io_error_from_errno (errsv),
|
||||
socket_strerror (errsv));
|
||||
#ifndef G_OS_WIN32
|
||||
/* Reset errno in case the caller wants to look at it */
|
||||
errno = errsv;
|
||||
#endif
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#if G_BYTE_ORDER == G_BIG_ENDIAN
|
||||
/* If the returned value is smaller than an int then we need to
|
||||
* slide it over into the low-order bytes of *value.
|
||||
*/
|
||||
if (size != sizeof (gint))
|
||||
*value = *value >> (8 * (sizeof (gint) - size));
|
||||
#endif
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_socket_set_option:
|
||||
* @socket: a #GSocket
|
||||
* @level: the "API level" of the option (eg, <literal>SOL_SOCKET</literal>)
|
||||
* @optname: the "name" of the option (eg, <literal>SO_BROADCAST</literal>)
|
||||
* @value: the value to set the option to
|
||||
* @error: #GError for error reporting, or %NULL to ignore.
|
||||
*
|
||||
* Sets the value of an integer-valued option on @socket, as with
|
||||
* <literal>setsockopt ()</literal>. (If you need to set a
|
||||
* non-integer-valued option, you will need to call
|
||||
* <literal>setsockopt ()</literal> directly.)
|
||||
*
|
||||
* The <link linkend="gio-gnetworking.h"><literal><gio/gnetworking.h></literal></link>
|
||||
* header pulls in system headers that will define most of the
|
||||
* standard/portable socket options. For unusual socket protocols or
|
||||
* platform-dependent options, you may need to include additional
|
||||
* headers.
|
||||
*
|
||||
* Returns: success or failure. On failure, @error will be set, and
|
||||
* the system error value (<literal>errno</literal> or
|
||||
* <literal>WSAGetLastError ()</literal>) will still be set to the
|
||||
* result of the <literal>setsockopt ()</literal> call.
|
||||
*
|
||||
* Since: 2.36
|
||||
*/
|
||||
gboolean
|
||||
g_socket_set_option (GSocket *socket,
|
||||
gint level,
|
||||
gint optname,
|
||||
gint value,
|
||||
GError **error)
|
||||
{
|
||||
gint errsv;
|
||||
|
||||
g_return_val_if_fail (G_IS_SOCKET (socket), FALSE);
|
||||
|
||||
if (setsockopt (socket->priv->fd, level, optname, &value, sizeof (gint)) == 0)
|
||||
return TRUE;
|
||||
|
||||
#if !defined (__linux__) && !defined (G_OS_WIN32)
|
||||
/* Linux and Windows let you set a single-byte value from an int,
|
||||
* but most other platforms don't.
|
||||
*/
|
||||
if (errno == EINVAL && value >= SCHAR_MIN && value <= CHAR_MAX)
|
||||
{
|
||||
#if G_BYTE_ORDER == G_BIG_ENDIAN
|
||||
value = value << (8 * (sizeof (gint) - 1));
|
||||
#endif
|
||||
if (setsockopt (socket->priv->fd, level, optname, &value, 1) == 0)
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
errsv = get_socket_errno ();
|
||||
|
||||
g_set_error_literal (error,
|
||||
G_IO_ERROR,
|
||||
socket_io_error_from_errno (errsv),
|
||||
socket_strerror (errsv));
|
||||
#ifndef G_OS_WIN32
|
||||
errno = errsv;
|
||||
#endif
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
@ -233,6 +233,19 @@ gssize g_socket_send_with_blocking (GSocket
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
GLIB_AVAILABLE_IN_2_36
|
||||
gboolean g_socket_get_option (GSocket *socket,
|
||||
gint level,
|
||||
gint optname,
|
||||
gint *value,
|
||||
GError **error);
|
||||
GLIB_AVAILABLE_IN_2_36
|
||||
gboolean g_socket_set_option (GSocket *socket,
|
||||
gint level,
|
||||
gint optname,
|
||||
gint value,
|
||||
GError **error);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __G_SOCKET_H__ */
|
||||
|
@ -13,10 +13,19 @@
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gunixconnection.h"
|
||||
#include "gnetworking.h"
|
||||
#include "gsocket.h"
|
||||
#include "gsocketcontrolmessage.h"
|
||||
#include "gunixcredentialsmessage.h"
|
||||
#include "gunixfdmessage.h"
|
||||
#include "glibintl.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/**
|
||||
* SECTION:gunixconnection
|
||||
* @title: GUnixConnection
|
||||
@ -37,16 +46,6 @@
|
||||
* Since: 2.22
|
||||
*/
|
||||
|
||||
#include <gio/gsocketcontrolmessage.h>
|
||||
#include <gio/gunixfdmessage.h>
|
||||
#include <gio/gnetworking.h>
|
||||
#include <gio/gsocket.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GUnixConnection, g_unix_connection,
|
||||
G_TYPE_SOCKET_CONNECTION,
|
||||
g_socket_connection_factory_register_type (g_define_type_id,
|
||||
@ -476,16 +475,14 @@ g_unix_connection_receive_credentials (GUnixConnection *connection,
|
||||
#ifdef __linux__
|
||||
{
|
||||
gint opt_val;
|
||||
socklen_t opt_len;
|
||||
|
||||
turn_off_so_passcreds = FALSE;
|
||||
opt_val = 0;
|
||||
opt_len = sizeof (gint);
|
||||
if (getsockopt (g_socket_get_fd (socket),
|
||||
SOL_SOCKET,
|
||||
SO_PASSCRED,
|
||||
&opt_val,
|
||||
&opt_len) != 0)
|
||||
if (!g_socket_get_option (socket,
|
||||
SOL_SOCKET,
|
||||
SO_PASSCRED,
|
||||
&opt_val,
|
||||
NULL))
|
||||
{
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
@ -494,24 +491,13 @@ g_unix_connection_receive_credentials (GUnixConnection *connection,
|
||||
strerror (errno));
|
||||
goto out;
|
||||
}
|
||||
if (opt_len != sizeof (gint))
|
||||
{
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
_("Unexpected option length while checking if SO_PASSCRED is enabled for socket. "
|
||||
"Expected %d bytes, got %d"),
|
||||
(gint) sizeof (gint), (gint) opt_len);
|
||||
goto out;
|
||||
}
|
||||
if (opt_val == 0)
|
||||
{
|
||||
opt_val = 1;
|
||||
if (setsockopt (g_socket_get_fd (socket),
|
||||
SOL_SOCKET,
|
||||
SO_PASSCRED,
|
||||
&opt_val,
|
||||
sizeof opt_val) != 0)
|
||||
if (!g_socket_set_option (socket,
|
||||
SOL_SOCKET,
|
||||
SO_PASSCRED,
|
||||
TRUE,
|
||||
NULL))
|
||||
{
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
@ -598,13 +584,11 @@ g_unix_connection_receive_credentials (GUnixConnection *connection,
|
||||
#ifdef __linux__
|
||||
if (turn_off_so_passcreds)
|
||||
{
|
||||
gint opt_val;
|
||||
opt_val = 0;
|
||||
if (setsockopt (g_socket_get_fd (socket),
|
||||
SOL_SOCKET,
|
||||
SO_PASSCRED,
|
||||
&opt_val,
|
||||
sizeof opt_val) != 0)
|
||||
if (!g_socket_set_option (socket,
|
||||
SOL_SOCKET,
|
||||
SO_PASSCRED,
|
||||
FALSE,
|
||||
NULL))
|
||||
{
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
|
Loading…
Reference in New Issue
Block a user