OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ipc/unix_domain_socket_util.h" | 5 #include "ipc/unix_domain_socket_util.h" |
6 | 6 |
7 #include <errno.h> | 7 #include <errno.h> |
8 #include <fcntl.h> | 8 #include <fcntl.h> |
9 #include <sys/socket.h> | 9 #include <sys/socket.h> |
10 #include <sys/stat.h> | 10 #include <sys/stat.h> |
11 #include <sys/un.h> | 11 #include <sys/un.h> |
12 #include <unistd.h> | 12 #include <unistd.h> |
13 | 13 |
14 #include "base/file_util.h" | 14 #include "base/file_util.h" |
15 #include "base/files/file_path.h" | 15 #include "base/files/file_path.h" |
16 #include "base/files/scoped_file.h" | |
17 #include "base/logging.h" | 16 #include "base/logging.h" |
18 #include "base/posix/eintr_wrapper.h" | 17 #include "base/posix/eintr_wrapper.h" |
19 | 18 |
20 namespace IPC { | 19 namespace IPC { |
21 | 20 |
22 // Verify that kMaxSocketNameLength is a decent size. | 21 // Verify that kMaxSocketNameLength is a decent size. |
23 COMPILE_ASSERT(sizeof(((sockaddr_un*)0)->sun_path) >= kMaxSocketNameLength, | 22 COMPILE_ASSERT(sizeof(((sockaddr_un*)0)->sun_path) >= kMaxSocketNameLength, |
24 BAD_SUN_PATH_LENGTH); | 23 BAD_SUN_PATH_LENGTH); |
25 | 24 |
26 namespace { | 25 namespace { |
(...skipping 12 matching lines...) Expand all Loading... |
39 return -1; | 38 return -1; |
40 } | 39 } |
41 // We reject socket_name.length() == kMaxSocketNameLength to make room for | 40 // We reject socket_name.length() == kMaxSocketNameLength to make room for |
42 // the NUL terminator at the end of the string. | 41 // the NUL terminator at the end of the string. |
43 if (socket_name.length() >= kMaxSocketNameLength) { | 42 if (socket_name.length() >= kMaxSocketNameLength) { |
44 LOG(ERROR) << "Socket name too long: " << socket_name; | 43 LOG(ERROR) << "Socket name too long: " << socket_name; |
45 return -1; | 44 return -1; |
46 } | 45 } |
47 | 46 |
48 // Create socket. | 47 // Create socket. |
49 base::ScopedFD fd(socket(AF_UNIX, SOCK_STREAM, 0)); | 48 int fd = socket(AF_UNIX, SOCK_STREAM, 0); |
50 if (!fd.is_valid()) { | 49 if (fd < 0) { |
51 PLOG(ERROR) << "socket"; | 50 PLOG(ERROR) << "socket"; |
52 return -1; | 51 return -1; |
53 } | 52 } |
| 53 file_util::ScopedFD scoped_fd(&fd); |
54 | 54 |
55 // Make socket non-blocking | 55 // Make socket non-blocking |
56 if (HANDLE_EINTR(fcntl(fd.get(), F_SETFL, O_NONBLOCK)) < 0) { | 56 if (HANDLE_EINTR(fcntl(fd, F_SETFL, O_NONBLOCK)) < 0) { |
57 PLOG(ERROR) << "fcntl(O_NONBLOCK)"; | 57 PLOG(ERROR) << "fcntl(O_NONBLOCK)"; |
58 return -1; | 58 return -1; |
59 } | 59 } |
60 | 60 |
61 // Create unix_addr structure. | 61 // Create unix_addr structure. |
62 memset(unix_addr, 0, sizeof(struct sockaddr_un)); | 62 memset(unix_addr, 0, sizeof(struct sockaddr_un)); |
63 unix_addr->sun_family = AF_UNIX; | 63 unix_addr->sun_family = AF_UNIX; |
64 strncpy(unix_addr->sun_path, socket_name.c_str(), kMaxSocketNameLength); | 64 strncpy(unix_addr->sun_path, socket_name.c_str(), kMaxSocketNameLength); |
65 *unix_addr_len = | 65 *unix_addr_len = |
66 offsetof(struct sockaddr_un, sun_path) + socket_name.length(); | 66 offsetof(struct sockaddr_un, sun_path) + socket_name.length(); |
67 return fd.release(); | 67 return *scoped_fd.release(); |
68 } | 68 } |
69 | 69 |
70 } // namespace | 70 } // namespace |
71 | 71 |
72 bool CreateServerUnixDomainSocket(const base::FilePath& socket_path, | 72 bool CreateServerUnixDomainSocket(const base::FilePath& socket_path, |
73 int* server_listen_fd) { | 73 int* server_listen_fd) { |
74 DCHECK(server_listen_fd); | 74 DCHECK(server_listen_fd); |
75 | 75 |
76 std::string socket_name = socket_path.value(); | 76 std::string socket_name = socket_path.value(); |
77 base::FilePath socket_dir = socket_path.DirName(); | 77 base::FilePath socket_dir = socket_path.DirName(); |
78 | 78 |
79 struct sockaddr_un unix_addr; | 79 struct sockaddr_un unix_addr; |
80 size_t unix_addr_len; | 80 size_t unix_addr_len; |
81 base::ScopedFD fd( | 81 int fd = MakeUnixAddrForPath(socket_name, &unix_addr, &unix_addr_len); |
82 MakeUnixAddrForPath(socket_name, &unix_addr, &unix_addr_len)); | 82 if (fd < 0) |
83 if (!fd.is_valid()) | |
84 return false; | 83 return false; |
| 84 file_util::ScopedFD scoped_fd(&fd); |
85 | 85 |
86 // Make sure the path we need exists. | 86 // Make sure the path we need exists. |
87 if (!base::CreateDirectory(socket_dir)) { | 87 if (!base::CreateDirectory(socket_dir)) { |
88 LOG(ERROR) << "Couldn't create directory: " << socket_dir.value(); | 88 LOG(ERROR) << "Couldn't create directory: " << socket_dir.value(); |
89 return false; | 89 return false; |
90 } | 90 } |
91 | 91 |
92 // Delete any old FS instances. | 92 // Delete any old FS instances. |
93 if (unlink(socket_name.c_str()) < 0 && errno != ENOENT) { | 93 if (unlink(socket_name.c_str()) < 0 && errno != ENOENT) { |
94 PLOG(ERROR) << "unlink " << socket_name; | 94 PLOG(ERROR) << "unlink " << socket_name; |
95 return false; | 95 return false; |
96 } | 96 } |
97 | 97 |
98 // Bind the socket. | 98 // Bind the socket. |
99 if (bind(fd.get(), reinterpret_cast<const sockaddr*>(&unix_addr), | 99 if (bind(fd, reinterpret_cast<const sockaddr*>(&unix_addr), |
100 unix_addr_len) < 0) { | 100 unix_addr_len) < 0) { |
101 PLOG(ERROR) << "bind " << socket_path.value(); | 101 PLOG(ERROR) << "bind " << socket_path.value(); |
102 return false; | 102 return false; |
103 } | 103 } |
104 | 104 |
105 // Start listening on the socket. | 105 // Start listening on the socket. |
106 if (listen(fd.get(), SOMAXCONN) < 0) { | 106 if (listen(fd, SOMAXCONN) < 0) { |
107 PLOG(ERROR) << "listen " << socket_path.value(); | 107 PLOG(ERROR) << "listen " << socket_path.value(); |
108 unlink(socket_name.c_str()); | 108 unlink(socket_name.c_str()); |
109 return false; | 109 return false; |
110 } | 110 } |
111 | 111 |
112 *server_listen_fd = fd.release(); | 112 *server_listen_fd = *scoped_fd.release(); |
113 return true; | 113 return true; |
114 } | 114 } |
115 | 115 |
116 bool CreateClientUnixDomainSocket(const base::FilePath& socket_path, | 116 bool CreateClientUnixDomainSocket(const base::FilePath& socket_path, |
117 int* client_socket) { | 117 int* client_socket) { |
118 DCHECK(client_socket); | 118 DCHECK(client_socket); |
119 | 119 |
120 std::string socket_name = socket_path.value(); | 120 std::string socket_name = socket_path.value(); |
121 base::FilePath socket_dir = socket_path.DirName(); | 121 base::FilePath socket_dir = socket_path.DirName(); |
122 | 122 |
123 struct sockaddr_un unix_addr; | 123 struct sockaddr_un unix_addr; |
124 size_t unix_addr_len; | 124 size_t unix_addr_len; |
125 base::ScopedFD fd( | 125 int fd = MakeUnixAddrForPath(socket_name, &unix_addr, &unix_addr_len); |
126 MakeUnixAddrForPath(socket_name, &unix_addr, &unix_addr_len)); | 126 if (fd < 0) |
127 if (!fd.is_valid()) | |
128 return false; | 127 return false; |
| 128 file_util::ScopedFD scoped_fd(&fd); |
129 | 129 |
130 if (HANDLE_EINTR(connect(fd.get(), reinterpret_cast<sockaddr*>(&unix_addr), | 130 if (HANDLE_EINTR(connect(fd, reinterpret_cast<sockaddr*>(&unix_addr), |
131 unix_addr_len)) < 0) { | 131 unix_addr_len)) < 0) { |
132 PLOG(ERROR) << "connect " << socket_path.value(); | 132 PLOG(ERROR) << "connect " << socket_path.value(); |
133 return false; | 133 return false; |
134 } | 134 } |
135 | 135 |
136 *client_socket = fd.release(); | 136 *client_socket = *scoped_fd.release(); |
137 return true; | 137 return true; |
138 } | 138 } |
139 | 139 |
140 bool GetPeerEuid(int fd, uid_t* peer_euid) { | 140 bool GetPeerEuid(int fd, uid_t* peer_euid) { |
141 DCHECK(peer_euid); | 141 DCHECK(peer_euid); |
142 #if defined(OS_MACOSX) || defined(OS_OPENBSD) || defined(OS_FREEBSD) | 142 #if defined(OS_MACOSX) || defined(OS_OPENBSD) || defined(OS_FREEBSD) |
143 uid_t socket_euid; | 143 uid_t socket_euid; |
144 gid_t socket_gid; | 144 gid_t socket_gid; |
145 if (getpeereid(fd, &socket_euid, &socket_gid) < 0) { | 145 if (getpeereid(fd, &socket_euid, &socket_gid) < 0) { |
146 PLOG(ERROR) << "getpeereid " << fd; | 146 PLOG(ERROR) << "getpeereid " << fd; |
(...skipping 30 matching lines...) Expand all Loading... |
177 | 177 |
178 bool IsRecoverableError(int err) { | 178 bool IsRecoverableError(int err) { |
179 return errno == ECONNABORTED || errno == EMFILE || errno == ENFILE || | 179 return errno == ECONNABORTED || errno == EMFILE || errno == ENFILE || |
180 errno == ENOMEM || errno == ENOBUFS; | 180 errno == ENOMEM || errno == ENOBUFS; |
181 } | 181 } |
182 | 182 |
183 bool ServerAcceptConnection(int server_listen_fd, int* server_socket) { | 183 bool ServerAcceptConnection(int server_listen_fd, int* server_socket) { |
184 DCHECK(server_socket); | 184 DCHECK(server_socket); |
185 *server_socket = -1; | 185 *server_socket = -1; |
186 | 186 |
187 base::ScopedFD accept_fd(HANDLE_EINTR(accept(server_listen_fd, NULL, 0))); | 187 int accept_fd = HANDLE_EINTR(accept(server_listen_fd, NULL, 0)); |
188 if (!accept_fd.is_valid()) | 188 if (accept_fd < 0) |
189 return IsRecoverableError(errno); | 189 return IsRecoverableError(errno); |
190 if (HANDLE_EINTR(fcntl(accept_fd.get(), F_SETFL, O_NONBLOCK)) < 0) { | 190 file_util::ScopedFD scoped_fd(&accept_fd); |
191 PLOG(ERROR) << "fcntl(O_NONBLOCK) " << accept_fd.get(); | 191 if (HANDLE_EINTR(fcntl(accept_fd, F_SETFL, O_NONBLOCK)) < 0) { |
| 192 PLOG(ERROR) << "fcntl(O_NONBLOCK) " << accept_fd; |
192 // It's safe to keep listening on |server_listen_fd| even if the attempt to | 193 // It's safe to keep listening on |server_listen_fd| even if the attempt to |
193 // set O_NONBLOCK failed on the client fd. | 194 // set O_NONBLOCK failed on the client fd. |
194 return true; | 195 return true; |
195 } | 196 } |
196 | 197 |
197 *server_socket = accept_fd.release(); | 198 *server_socket = *scoped_fd.release(); |
198 return true; | 199 return true; |
199 } | 200 } |
200 | 201 |
201 } // namespace IPC | 202 } // namespace IPC |
OLD | NEW |