Browse files

socket: set the close-on-exec flag

Copy the fd_util library from MPD, which provides wrappers for setting
O_CLOEXEC and O_NONBLOCK.
  • Loading branch information...
1 parent 8979f27 commit 3fdd0e9aeddfe163cfce08be3c9ab86e41d73470 @MaxKellermann MaxKellermann committed Nov 8, 2009
Showing with 169 additions and 18 deletions.
  1. +1 −0 Makefile.am
  2. +1 −0 NEWS
  3. +118 −0 src/fd_util.c
  4. +46 −0 src/fd_util.h
  5. +3 −18 src/socket.c
View
1 Makefile.am
@@ -51,6 +51,7 @@ src_libmpdclient_la_SOURCES = \
src/directory.c \
src/rdirectory.c \
src/error.c \
+ src/fd_util.c src/fd_util.h \
src/output.c \
src/coutput.c \
src/entity.c \
View
1 NEWS
@@ -3,6 +3,7 @@ libmpdclient 2.1 (2009/??/??)
* song: copy last_modified value in mpd_song_dup()
* socket, async: use WSAGetLastError() instead of errno on WIN32
* socket: connect in non-blocking mode
+* socket: set the close-on-exec flag
* sync: optimistic write, reduce select() calls
* Makefile.am: use --version-script only with GNU ld
* added library version compile-time checks
View
118 src/fd_util.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2003-2009 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code is copied from MPD. It is a subset of the original
+ * library (we don't need pipes and regular files in libmpdclient).
+ *
+ */
+
+#include "fd_util.h"
+
+#include <assert.h>
+#include <stdbool.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#ifdef WIN32
+#include <winsock2.h>
+#else
+#include <sys/socket.h>
+#endif
+
+#ifndef WIN32
+
+static int
+fd_mask_flags(int fd, int and_mask, int xor_mask)
+{
+ int ret;
+
+ assert(fd >= 0);
+
+ ret = fcntl(fd, F_GETFD, 0);
+ if (ret < 0)
+ return ret;
+
+ return fcntl(fd, F_SETFD, (ret & and_mask) ^ xor_mask);
+}
+
+#endif /* !WIN32 */
+
+static int
+fd_set_cloexec(int fd, bool enable)
+{
+#ifndef WIN32
+ return fd_mask_flags(fd, ~FD_CLOEXEC, enable ? FD_CLOEXEC : 0);
+#else
+ (void)fd;
+ (void)enable;
+#endif
+}
+
+/**
+ * Enables non-blocking mode for the specified file descriptor. On
+ * WIN32, this function only works for sockets.
+ */
+static int
+fd_set_nonblock(int fd)
+{
+#ifdef WIN32
+ u_long val = 1;
+ return ioctlsocket(fd, FIONBIO, &val);
+#else
+ int flags;
+
+ assert(fd >= 0);
+
+ flags = fcntl(fd, F_GETFL);
+ if (flags < 0)
+ return flags;
+
+ return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+#endif
+}
+
+int
+socket_cloexec_nonblock(int domain, int type, int protocol)
+{
+ int fd;
+
+#if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK)
+ fd = socket(domain, type | SOCK_CLOEXEC | SOCK_NONBLOCK, protocol);
+ if (fd >= 0 || errno != EINVAL)
+ return fd;
+#endif
+
+ fd = socket(domain, type, protocol);
+ if (fd >= 0) {
+ fd_set_cloexec(fd, true);
+ fd_set_nonblock(fd);
+ }
+
+ return fd;
+}
View
46 src/fd_util.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2003-2009 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This library provides easy helper functions for working with file
+ * descriptors. It has wrappers for taking advantage of Linux 2.6
+ * specific features like O_CLOEXEC.
+ *
+ */
+
+#ifndef FD_UTIL_H
+#define FD_UTIL_H
+
+/**
+ * Wrapper for socket(), which sets the CLOEXEC and the NONBLOCK flag
+ * (atomically if supported by the OS).
+ */
+int
+socket_cloexec_nonblock(int domain, int type, int protocol);
+
+#endif
View
21 src/socket.c
@@ -27,6 +27,7 @@
*/
#include "socket.h"
+#include "fd_util.h"
#include "resolver.h"
#include "ierror.h"
@@ -84,21 +85,6 @@ mpd_socket_global_init(struct mpd_error_info *error)
#endif
/**
- * Put the socket into non-blocking mode.
- */
-static void
-disable_blocking(int fd)
-{
-#ifdef WIN32
- u_long iMode = 1; /* 0 = blocking, else non-blocking */
- ioctlsocket(fd, FIONBIO, &iMode);
-#else /* !WIN32 */
- int flags = fcntl(fd, F_GETFL, 0);
- fcntl(fd, F_SETFL, flags | O_NONBLOCK);
-#endif
-}
-
-/**
* Wait for the socket to become readable.
*/
static int
@@ -165,15 +151,14 @@ mpd_socket_connect(const char *host, unsigned port, const struct timeval *tv0,
assert(!mpd_error_is_defined(error));
while ((address = resolver_next(resolver)) != NULL) {
- fd = socket(address->family, SOCK_STREAM, address->protocol);
+ fd = socket_cloexec_nonblock(address->family, SOCK_STREAM,
+ address->protocol);
if (fd < 0) {
mpd_error_clear(error);
mpd_error_errno(error);
continue;
}
- disable_blocking(fd);
-
ret = connect(fd, address->addr, address->addrlen);
if (ret == 0) {
resolver_free(resolver);

0 comments on commit 3fdd0e9

Please sign in to comment.