• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*
2   * Copyright © 2012 Collabora, Ltd.
3   *
4   * Permission is hereby granted, free of charge, to any person obtaining
5   * a copy of this software and associated documentation files (the
6   * "Software"), to deal in the Software without restriction, including
7   * without limitation the rights to use, copy, modify, merge, publish,
8   * distribute, sublicense, and/or sell copies of the Software, and to
9   * permit persons to whom the Software is furnished to do so, subject to
10   * the following conditions:
11   *
12   * The above copyright notice and this permission notice (including the
13   * next paragraph) shall be included in all copies or substantial
14   * portions of the Software.
15   *
16   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17   * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18   * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19   * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20   * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21   * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22   * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23   * SOFTWARE.
24   */
25  
26  #define _GNU_SOURCE
27  
28  #include <sys/types.h>
29  #include <sys/socket.h>
30  #include <unistd.h>
31  #include <fcntl.h>
32  #include <errno.h>
33  #include <sys/epoll.h>
34  
35  #include "../config.h"
36  #include "wayland-os.h"
37  
38  static int
set_cloexec_or_close(int fd)39  set_cloexec_or_close(int fd)
40  {
41  	long flags;
42  
43  	if (fd == -1)
44  		return -1;
45  
46  	flags = fcntl(fd, F_GETFD);
47  	if (flags == -1)
48  		goto err;
49  
50  	if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
51  		goto err;
52  
53  	return fd;
54  
55  err:
56  	close(fd);
57  	return -1;
58  }
59  
60  int
wl_os_socket_cloexec(int domain,int type,int protocol)61  wl_os_socket_cloexec(int domain, int type, int protocol)
62  {
63  	int fd;
64  
65  	fd = socket(domain, type | SOCK_CLOEXEC, protocol);
66  	if (fd >= 0)
67  		return fd;
68  	if (errno != EINVAL)
69  		return -1;
70  
71  	fd = socket(domain, type, protocol);
72  	return set_cloexec_or_close(fd);
73  }
74  
75  int
wl_os_dupfd_cloexec(int fd,long minfd)76  wl_os_dupfd_cloexec(int fd, long minfd)
77  {
78  	int newfd;
79  
80  	newfd = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
81  	if (newfd >= 0)
82  		return newfd;
83  	if (errno != EINVAL)
84  		return -1;
85  
86  	newfd = fcntl(fd, F_DUPFD, minfd);
87  	return set_cloexec_or_close(newfd);
88  }
89  
90  static ssize_t
recvmsg_cloexec_fallback(int sockfd,struct msghdr * msg,int flags)91  recvmsg_cloexec_fallback(int sockfd, struct msghdr *msg, int flags)
92  {
93  	ssize_t len;
94  	struct cmsghdr *cmsg;
95  	unsigned char *data;
96  	int *fd;
97  	int *end;
98  
99  	len = recvmsg(sockfd, msg, flags);
100  	if (len == -1)
101  		return -1;
102  
103  	if (!msg->msg_control || msg->msg_controllen == 0)
104  		return len;
105  
106  	cmsg = CMSG_FIRSTHDR(msg);
107  	for (; cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) {
108  		if (cmsg->cmsg_level != SOL_SOCKET ||
109  		    cmsg->cmsg_type != SCM_RIGHTS)
110  			continue;
111  
112  		data = CMSG_DATA(cmsg);
113  		end = (int *)(data + cmsg->cmsg_len - CMSG_LEN(0));
114  		for (fd = (int *)data; fd < end; ++fd)
115  			*fd = set_cloexec_or_close(*fd);
116  	}
117  
118  	return len;
119  }
120  
121  ssize_t
wl_os_recvmsg_cloexec(int sockfd,struct msghdr * msg,int flags)122  wl_os_recvmsg_cloexec(int sockfd, struct msghdr *msg, int flags)
123  {
124  	ssize_t len;
125  
126  	len = recvmsg(sockfd, msg, flags | MSG_CMSG_CLOEXEC);
127  	if (len >= 0)
128  		return len;
129  	if (errno != EINVAL)
130  		return -1;
131  
132  	return recvmsg_cloexec_fallback(sockfd, msg, flags);
133  }
134  
135  int
wl_os_epoll_create_cloexec(void)136  wl_os_epoll_create_cloexec(void)
137  {
138  	int fd;
139  
140  #ifdef EPOLL_CLOEXEC
141  	fd = epoll_create1(EPOLL_CLOEXEC);
142  	if (fd >= 0)
143  		return fd;
144  	if (errno != EINVAL)
145  		return -1;
146  #endif
147  
148  	fd = epoll_create(1);
149  	return set_cloexec_or_close(fd);
150  }
151  
152  int
wl_os_accept_cloexec(int sockfd,struct sockaddr * addr,socklen_t * addrlen)153  wl_os_accept_cloexec(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
154  {
155  	int fd;
156  
157  #ifdef HAVE_ACCEPT4
158  	fd = accept4(sockfd, addr, addrlen, SOCK_CLOEXEC);
159  	if (fd >= 0)
160  		return fd;
161  	if (errno != ENOSYS)
162  		return -1;
163  #endif
164  
165  	fd = accept(sockfd, addr, addrlen);
166  	return set_cloexec_or_close(fd);
167  }
168