1 /*
2  * Copyright (c) 2015 DeNA Co., Ltd.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to
6  * deal in the Software without restriction, including without limitation the
7  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8  * sell copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20  * IN THE SOFTWARE.
21  */
22 #include <fcntl.h>
23 #include "cloexec.h"
24 
25 pthread_mutex_t cloexec_mutex = PTHREAD_MUTEX_INITIALIZER;
26 
set_cloexec(int fd)27 static int set_cloexec(int fd)
28 {
29     return fcntl(fd, F_SETFD, FD_CLOEXEC) != -1 ? 0 : -1;
30 }
31 
32 /*
33  * note: the socket must be in non-blocking mode, or the call might block while the mutex is being locked
34  */
cloexec_accept(int socket,struct sockaddr * addr,socklen_t * addrlen)35 int cloexec_accept(int socket, struct sockaddr *addr, socklen_t *addrlen)
36 {
37     int fd;
38     pthread_mutex_lock(&cloexec_mutex);
39 
40     if ((fd = accept(socket, addr, addrlen)) == -1)
41         goto Exit;
42     if (set_cloexec(fd) != 0) {
43         close(fd);
44         fd = -1;
45         goto Exit;
46     }
47 
48 Exit:
49     pthread_mutex_unlock(&cloexec_mutex);
50     return fd;
51 }
52 
cloexec_pipe(int fds[2])53 int cloexec_pipe(int fds[2])
54 {
55 #ifdef __linux__
56 #ifndef _GNU_SOURCE
57     extern int pipe2(int pipefd[2], int flags);
58 #endif
59     return pipe2(fds, O_CLOEXEC);
60 #else
61     int ret = -1;
62     pthread_mutex_lock(&cloexec_mutex);
63 
64     if (pipe(fds) != 0)
65         goto Exit;
66     if (set_cloexec(fds[0]) != 0 || set_cloexec(fds[1]) != 0)
67         goto Exit;
68     ret = 0;
69 
70 Exit:
71     pthread_mutex_unlock(&cloexec_mutex);
72     return ret;
73 #endif
74 }
75 
cloexec_socket(int domain,int type,int protocol)76 int cloexec_socket(int domain, int type, int protocol)
77 {
78 #ifdef __linux__
79     return socket(domain, type | SOCK_CLOEXEC, protocol);
80 #else
81     int fd = -1;
82     pthread_mutex_lock(&cloexec_mutex);
83 
84     if ((fd = socket(domain, type, protocol)) == -1)
85         goto Exit;
86     if (set_cloexec(fd) != 0) {
87         close(fd);
88         fd = -1;
89         goto Exit;
90     }
91 
92 Exit:
93     pthread_mutex_unlock(&cloexec_mutex);
94     return fd;
95 #endif
96 }
97