#include "gsocket.h"
+#ifdef G_OS_UNIX
+#include "glib-unix.h"
+#endif
+
#include <errno.h>
#include <signal.h>
#include <string.h>
set_fd_nonblocking (int fd)
{
#ifndef G_OS_WIN32
- glong arg;
+ GError *error = NULL;
#else
gulong arg;
#endif
#ifndef G_OS_WIN32
- if ((arg = fcntl (fd, F_GETFL, NULL)) < 0)
+ if (!g_unix_set_fd_nonblocking (fd, TRUE, &error))
{
- g_warning ("Error getting socket status flags: %s", socket_strerror (errno));
- arg = 0;
+ g_warning ("Error setting socket nonblocking: %s", error->message);
+ g_clear_error (&error);
}
-
- arg = arg | O_NONBLOCK;
-
- if (fcntl (fd, F_SETFL, arg) < 0)
- g_warning ("Error setting socket status flags: %s", socket_strerror (errno));
#else
arg = TRUE;
else
msg.msg_flags = 0;
+ /* We always set the close-on-exec flag so we don't leak file
+ * descriptors into child processes. Note that gunixfdmessage.c
+ * will later call fcntl (fd, FD_CLOEXEC), but that isn't atomic.
+ */
+#ifdef MSG_CMSG_CLOEXEC
+ msg.msg_flags |= MSG_CMSG_CLOEXEC;
+#endif
+
/* do it */
while (1)
{
return -1;
result = recvmsg (socket->priv->fd, &msg, msg.msg_flags);
+#ifdef MSG_CMSG_CLOEXEC
+ if (result < 0 && get_socket_errno () == EINVAL)
+ {
+ /* We must be running on an old kernel. Call without the flag. */
+ msg.msg_flags &= ~(MSG_CMSG_CLOEXEC);
+ result = recvmsg (socket->priv->fd, &msg, msg.msg_flags);
+ }
+#endif
if (result < 0)
{