diff options
Diffstat (limited to 'gio/gsocket.c')
-rw-r--r-- | gio/gsocket.c | 89 |
1 files changed, 51 insertions, 38 deletions
diff --git a/gio/gsocket.c b/gio/gsocket.c index 2dc005b63..22a8dd7ec 100644 --- a/gio/gsocket.c +++ b/gio/gsocket.c @@ -587,7 +587,38 @@ g_socket_details_from_fd (GSocket *socket) socket_strerror (errsv)); } -/* Wrapper around socket() that is shared with gnetworkmonitornetlink.c */ +static void +socket_set_nonblock (int fd) +{ +#ifndef G_OS_WIN32 + GError *error = NULL; +#else + gulong arg; +#endif + + /* Always use native nonblocking sockets, as Windows sets sockets to + * nonblocking automatically in certain operations. This way we make + * things work the same on all platforms. + */ +#ifndef G_OS_WIN32 + if (!g_unix_set_fd_nonblocking (fd, TRUE, &error)) + { + g_warning ("Error setting socket to nonblocking mode: %s", error->message); + g_clear_error (&error); + } +#else + arg = TRUE; + + if (ioctlsocket (fd, FIONBIO, &arg) == SOCKET_ERROR) + { + int errsv = get_socket_errno (); + g_warning ("Error setting socket status flags: %s", socket_strerror (errsv)); + } +#endif +} + +/* Wrapper around socket() that is shared with gnetworkmonitornetlink.c. + * It always sets SOCK_CLOEXEC | SOCK_NONBLOCK. */ gint g_socket (gint domain, gint type, @@ -596,13 +627,13 @@ g_socket (gint domain, { int fd, errsv; -#ifdef SOCK_CLOEXEC - fd = socket (domain, type | SOCK_CLOEXEC, protocol); +#if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK) + fd = socket (domain, type | SOCK_CLOEXEC | SOCK_NONBLOCK, protocol); errsv = errno; if (fd != -1) return fd; - /* It's possible that libc has SOCK_CLOEXEC but the kernel does not */ + /* It's possible that libc has SOCK_CLOEXEC and/or SOCK_NONBLOCK but the kernel does not */ if (fd < 0 && (errsv == EINVAL || errsv == EPROTOTYPE)) #endif fd = socket (domain, type, protocol); @@ -644,9 +675,13 @@ g_socket (gint domain, } #endif + /* Ensure the socket is non-blocking. */ + socket_set_nonblock (fd); + return fd; } +/* Returned socket has SOCK_CLOEXEC | SOCK_NONBLOCK set. */ static gint g_socket_create_socket (GSocketFamily family, GSocketType type, @@ -696,44 +731,22 @@ g_socket_constructed (GObject *object) GSocket *socket = G_SOCKET (object); if (socket->priv->fd >= 0) - /* create socket->priv info from the fd */ - g_socket_details_from_fd (socket); - + { + /* create socket->priv info from the fd and ensure it’s non-blocking */ + g_socket_details_from_fd (socket); + socket_set_nonblock (socket->priv->fd); + } else - /* create the fd from socket->priv info */ - socket->priv->fd = g_socket_create_socket (socket->priv->family, - socket->priv->type, - socket->priv->protocol, - &socket->priv->construct_error); + { + /* create the fd from socket->priv info; this sets it non-blocking by construction */ + socket->priv->fd = g_socket_create_socket (socket->priv->family, + socket->priv->type, + socket->priv->protocol, + &socket->priv->construct_error); + } if (socket->priv->fd != -1) { -#ifndef G_OS_WIN32 - GError *error = NULL; -#else - gulong arg; -#endif - - /* Always use native nonblocking sockets, as Windows sets sockets to - * nonblocking automatically in certain operations. This way we make - * things work the same on all platforms. - */ -#ifndef G_OS_WIN32 - if (!g_unix_set_fd_nonblocking (socket->priv->fd, TRUE, &error)) - { - g_warning ("Error setting socket nonblocking: %s", error->message); - g_clear_error (&error); - } -#else - arg = TRUE; - - if (ioctlsocket (socket->priv->fd, FIONBIO, &arg) == SOCKET_ERROR) - { - int errsv = get_socket_errno (); - g_warning ("Error setting socket status flags: %s", socket_strerror (errsv)); - } -#endif - #ifdef SO_NOSIGPIPE /* See note about SIGPIPE below. */ g_socket_set_option (socket, SOL_SOCKET, SO_NOSIGPIPE, TRUE, NULL); |