[glib] gsocket: add getsockopt/setsockopt wrappers
- From: Dan Winship <danw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib] gsocket: add getsockopt/setsockopt wrappers
- Date: Wed, 12 Dec 2012 14:21:57 +0000 (UTC)
commit 211ed1775dfc514077984d0fea5d2529dcc5036e
Author: Dan Winship <danw gnome org>
Date: Mon Feb 13 21:12:34 2012 -0500
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
configure.ac | 38 ++--
docs/reference/gio/gio-sections.txt | 2 +
gio/gio.symbols | 2 +
gio/gnetworkmonitornetlink.c | 21 +-
gio/gsocket.c | 356 +++++++++++++++++++++--------------
gio/gsocket.h | 13 ++
gio/gunixconnection.c | 64 +++----
7 files changed, 288 insertions(+), 208 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index e08b255..bf4d938 100644
--- a/configure.ac
+++ b/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)
-
-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], [
+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)
+
# We can't just use AC_CHECK_FUNC/AC_CHECK_LIB here. Bug 586150
NETWORK_LIBS=""
AC_MSG_CHECKING([for res_query])
diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt
index c9efdc5..81f613c 100644
--- a/docs/reference/gio/gio-sections.txt
+++ b/docs/reference/gio/gio-sections.txt
@@ -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
diff --git a/gio/gio.symbols b/gio/gio.symbols
index c97e2bd..b148333 100644
--- a/gio/gio.symbols
+++ b/gio/gio.symbols
@@ -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
diff --git a/gio/gnetworkmonitornetlink.c b/gio/gnetworkmonitornetlink.c
index a276c58..3f67654 100644
--- a/gio/gnetworkmonitornetlink.c
+++ b/gio/gnetworkmonitornetlink.c
@@ -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,22 +112,21 @@ g_network_monitor_netlink_initable_init (GInitable *initable,
return FALSE;
}
- val = 1;
- if (setsockopt (sockfd, SOL_SOCKET, SO_PASSCRED, &val, sizeof (val)) != 0)
+ nl->priv->sock = g_socket_new_from_fd (sockfd, error);
+ if (error)
{
- 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));
+ g_prefix_error (error, "%s", _("Could not create network monitor: "));
close (sockfd);
return FALSE;
}
- nl->priv->sock = g_socket_new_from_fd (sockfd, error);
- if (error)
+ if (!g_socket_set_option (nl->priv->sock, SOL_SOCKET, SO_PASSCRED,
+ TRUE, NULL))
{
- g_prefix_error (error, "%s", _("Could not create network monitor: "));
- close (sockfd);
+ 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;
}
diff --git a/gio/gsocket.c b/gio/gsocket.c
index 548b348..e2fec92 100644
--- a/gio/gsocket.c
+++ b/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;
+}
+
diff --git a/gio/gsocket.h b/gio/gsocket.h
index 29ba44f..6d54ef0 100644
--- a/gio/gsocket.h
+++ b/gio/gsocket.h
@@ -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__ */
diff --git a/gio/gunixconnection.c b/gio/gunixconnection.c
index 8a0968e..1c94051 100644
--- a/gio/gunixconnection.c
+++ b/gio/gunixconnection.c
@@ -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,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]