blob: 82baad3730b52f82d942d06e3cbf90c88f793a8b [file] [log] [blame]
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -07001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#include "common/libs/fs/shared_fd.h"
17
18#include <sys/types.h>
19#include <sys/stat.h>
Ping-Hao Wu75cc1e02017-06-06 16:39:14 -070020#include <cstddef>
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -070021#include <errno.h>
22#include <fcntl.h>
23#include <netinet/in.h>
24#include <unistd.h>
Jorge E. Moreiracfbb4102018-07-02 18:53:24 -070025#include <algorithm>
Cody Schuffelen4ede79d2019-11-13 13:24:12 -080026#include <vector>
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -070027
Greg Hartman40b88f52017-06-22 15:34:11 -070028#include "common/libs/glog/logging.h"
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -070029#include "common/libs/fs/shared_select.h"
30
31// #define ENABLE_GCE_SHARED_FD_LOGGING 1
32
33namespace {
Greg Hartman153b1062017-11-11 12:09:21 -080034using cvd::SharedFDSet;
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -070035
36void MarkAll(const SharedFDSet& input, fd_set* dest, int* max_index) {
37 for (SharedFDSet::const_iterator it = input.begin(); it != input.end();
38 ++it) {
39 (*it)->Set(dest, max_index);
40 }
41}
42
Tomasz Wiszkowski09c17782017-09-15 09:54:49 -070043void CheckMarked(fd_set* in_out_mask, SharedFDSet* in_out_set) {
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -070044 if (!in_out_set) {
45 return;
46 }
47 SharedFDSet save;
48 save.swap(in_out_set);
49 for (SharedFDSet::iterator it = save.begin(); it != save.end(); ++it) {
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -070050 if ((*it)->IsSet(in_out_mask)) {
51 in_out_set->Set(*it);
52 }
53 }
54}
55} // namespace
56
Greg Hartman153b1062017-11-11 12:09:21 -080057namespace cvd {
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -070058
59bool FileInstance::CopyFrom(FileInstance& in) {
Cody Schuffelen4ede79d2019-11-13 13:24:12 -080060 std::vector<char> buffer(8192);
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -070061 while (true) {
62 ssize_t num_read = in.Read(buffer.data(), buffer.size());
63 if (!num_read) {
64 return true;
65 }
66 if (num_read == -1) {
67 return false;
68 }
69 if (num_read > 0) {
70 if (Write(buffer.data(), num_read) != num_read) {
71 // The caller will have to log an appropriate message.
72 return false;
73 }
74 }
75 }
76 return true;
77}
78
Jorge E. Moreiracfbb4102018-07-02 18:53:24 -070079bool FileInstance::CopyFrom(FileInstance& in, size_t length) {
Cody Schuffelen4ede79d2019-11-13 13:24:12 -080080 std::vector<char> buffer(8192);
Jorge E. Moreiracfbb4102018-07-02 18:53:24 -070081 while (length > 0) {
82 ssize_t num_read = in.Read(buffer.data(), std::min(buffer.size(), length));
83 length -= num_read;
84 if (num_read <= 0) {
85 return false;
86 }
87 if (Write(buffer.data(), num_read) != num_read) {
88 // The caller will have to log an appropriate message.
89 return false;
90 }
91 }
92 return true;
93}
94
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -070095void FileInstance::Close() {
Cody Schuffelen4ede79d2019-11-13 13:24:12 -080096 std::stringstream message;
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -070097 if (fd_ == -1) {
98 errno_ = EBADF;
99 } else if (close(fd_) == -1) {
100 errno_ = errno;
101 if (identity_.size()) {
Cody Schuffelen4ede79d2019-11-13 13:24:12 -0800102 message << __FUNCTION__ << ": " << identity_ << " failed (" << StrError() << ")";
103 std::string message_str = message.str();
104 Log(message_str.c_str());
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700105 }
106 } else {
107 if (identity_.size()) {
Cody Schuffelen4ede79d2019-11-13 13:24:12 -0800108 message << __FUNCTION__ << ": " << identity_ << "succeeded";
109 std::string message_str = message.str();
110 Log(message_str.c_str());
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700111 }
112 }
113 fd_ = -1;
114}
115
116void FileInstance::Identify(const char* identity) {
Cody Schuffelen4ede79d2019-11-13 13:24:12 -0800117 std::stringstream identity_stream;
118 identity_stream << "fd=" << fd_ << " @" << this << " is " << identity;
119 identity_ = identity_stream.str();
120 std::stringstream message;
121 message << __FUNCTION__ << ": " << identity_;
122 std::string message_str = message.str();
123 Log(message_str.c_str());
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700124}
125
126bool FileInstance::IsSet(fd_set* in) const {
127 if (IsOpen() && FD_ISSET(fd_, in)) {
128 return true;
129 }
130 return false;
131}
132
133#if ENABLE_GCE_SHARED_FD_LOGGING
134void FileInstance::Log(const char* message) {
Greg Hartman67fa8582017-07-31 21:40:02 -0700135 LOG(INFO) << message;
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700136}
137#else
Tomasz Wiszkowskid88403b2017-07-06 14:42:14 -0700138void FileInstance::Log(const char*) {}
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700139#endif
140
141void FileInstance::Set(fd_set* dest, int* max_index) const {
142 if (!IsOpen()) {
143 return;
144 }
145 if (fd_ >= *max_index) {
146 *max_index = fd_ + 1;
147 }
148 FD_SET(fd_, dest);
149}
150
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700151int Select(SharedFDSet* read_set, SharedFDSet* write_set,
152 SharedFDSet* error_set, struct timeval* timeout) {
153 int max_index = 0;
154 fd_set readfds;
155 FD_ZERO(&readfds);
156 if (read_set) {
157 MarkAll(*read_set, &readfds, &max_index);
158 }
159 fd_set writefds;
160 FD_ZERO(&writefds);
161 if (write_set) {
162 MarkAll(*write_set, &writefds, &max_index);
163 }
164 fd_set errorfds;
165 FD_ZERO(&errorfds);
Tomasz Wiszkowski09c17782017-09-15 09:54:49 -0700166 if (error_set) {
167 MarkAll(*error_set, &errorfds, &max_index);
168 }
169
Tomasz Wiszkowskid88403b2017-07-06 14:42:14 -0700170 int rval = TEMP_FAILURE_RETRY(
171 select(max_index, &readfds, &writefds, &errorfds, timeout));
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700172 FileInstance::Log("select\n");
Tomasz Wiszkowski09c17782017-09-15 09:54:49 -0700173 CheckMarked(&readfds, read_set);
174 CheckMarked(&writefds, write_set);
175 CheckMarked(&errorfds, error_set);
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700176 return rval;
177}
178
Tomasz Wiszkowskid88403b2017-07-06 14:42:14 -0700179static void MakeAddress(const char* name, bool abstract,
180 struct sockaddr_un* dest, socklen_t* len) {
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700181 memset(dest, 0, sizeof(*dest));
182 dest->sun_family = AF_UNIX;
183 // sun_path is NOT expected to be nul-terminated.
184 // See man 7 unix.
Ping-Hao Wu75cc1e02017-06-06 16:39:14 -0700185 size_t namelen;
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700186 if (abstract) {
Ping-Hao Wu75cc1e02017-06-06 16:39:14 -0700187 // ANDROID_SOCKET_NAMESPACE_ABSTRACT
188 namelen = strlen(name);
189 CHECK_LE(namelen, sizeof(dest->sun_path) - 1)
190 << "MakeAddress failed. Name=" << name << " is longer than allowed.";
191 dest->sun_path[0] = 0;
192 memcpy(dest->sun_path + 1, name, namelen);
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700193 } else {
Ping-Hao Wu75cc1e02017-06-06 16:39:14 -0700194 // ANDROID_SOCKET_NAMESPACE_RESERVED
195 // ANDROID_SOCKET_NAMESPACE_FILESYSTEM
196 // TODO(pinghao): Distinguish between them?
197 namelen = strlen(name);
198 CHECK_LE(namelen, sizeof(dest->sun_path))
199 << "MakeAddress failed. Name=" << name << " is longer than allowed.";
200 strncpy(dest->sun_path, name, strlen(name));
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700201 }
Ping-Hao Wu75cc1e02017-06-06 16:39:14 -0700202 *len = namelen + offsetof(struct sockaddr_un, sun_path) + 1;
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700203}
204
205SharedFD SharedFD::SocketSeqPacketServer(const char* name, mode_t mode) {
206 return SocketLocalServer(name, false, SOCK_SEQPACKET, mode);
207}
208
209SharedFD SharedFD::SocketSeqPacketClient(const char* name) {
210 return SocketLocalClient(name, false, SOCK_SEQPACKET);
211}
212
Tomasz Wiszkowskiaf38c7c2017-08-14 12:33:11 -0700213SharedFD SharedFD::TimerFD(int clock, int flags) {
214 int fd = timerfd_create(clock, flags);
215 if (fd == -1) {
216 return SharedFD(std::shared_ptr<FileInstance>(new FileInstance(fd, errno)));
217 } else {
218 return SharedFD(std::shared_ptr<FileInstance>(new FileInstance(fd, 0)));
219 }
220}
221
Tomasz Wiszkowskid88403b2017-07-06 14:42:14 -0700222SharedFD SharedFD::Accept(const FileInstance& listener, struct sockaddr* addr,
223 socklen_t* addrlen) {
224 return SharedFD(
225 std::shared_ptr<FileInstance>(listener.Accept(addr, addrlen)));
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700226}
227
228SharedFD SharedFD::Accept(const FileInstance& listener) {
229 return SharedFD::Accept(listener, NULL, NULL);
230}
231
Greg Hartman3c95aac2017-06-14 18:24:26 -0700232SharedFD SharedFD::Dup(int unmanaged_fd) {
Cody Schuffelen213600a2019-11-18 18:52:59 -0800233 int fd = fcntl(unmanaged_fd, F_DUPFD_CLOEXEC, 3);
234 int error_num = errno;
235 return SharedFD(std::shared_ptr<FileInstance>(new FileInstance(fd, error_num)));
Greg Hartman3c95aac2017-06-14 18:24:26 -0700236}
237
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700238bool SharedFD::Pipe(SharedFD* fd0, SharedFD* fd1) {
239 int fds[2];
240 int rval = pipe(fds);
241 if (rval != -1) {
242 (*fd0) = std::shared_ptr<FileInstance>(new FileInstance(fds[0], errno));
243 (*fd1) = std::shared_ptr<FileInstance>(new FileInstance(fds[1], errno));
244 return true;
245 }
246 return false;
247}
248
Tomasz Wiszkowskid88403b2017-07-06 14:42:14 -0700249SharedFD SharedFD::Event(int initval, int flags) {
Cody Schuffelenb11b4602019-08-28 16:04:33 -0700250 int fd = eventfd(initval, flags);
251 return std::shared_ptr<FileInstance>(new FileInstance(fd, errno));
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700252}
253
Tomasz Wiszkowski16fb1742017-09-15 14:31:53 -0700254SharedFD SharedFD::Epoll(int flags) {
Cody Schuffelenb11b4602019-08-28 16:04:33 -0700255 int fd = epoll_create1(flags);
256 return std::shared_ptr<FileInstance>(new FileInstance(fd, errno));
Tomasz Wiszkowski16fb1742017-09-15 14:31:53 -0700257}
258
Jorge E. Moreira8e9793e2018-11-05 21:57:26 -0800259bool SharedFD::SocketPair(int domain, int type, int protocol,
260 SharedFD* fd0, SharedFD* fd1) {
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700261 int fds[2];
262 int rval = socketpair(domain, type, protocol, fds);
Tomasz Wiszkowskid88403b2017-07-06 14:42:14 -0700263 if (rval != -1) {
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700264 (*fd0) = std::shared_ptr<FileInstance>(new FileInstance(fds[0], errno));
265 (*fd1) = std::shared_ptr<FileInstance>(new FileInstance(fds[1], errno));
266 return true;
267 }
268 return false;
269}
270
271SharedFD SharedFD::Open(const char* path, int flags, mode_t mode) {
272 int fd = TEMP_FAILURE_RETRY(open(path, flags, mode));
273 if (fd == -1) {
274 return SharedFD(std::shared_ptr<FileInstance>(new FileInstance(fd, errno)));
275 } else {
276 return SharedFD(std::shared_ptr<FileInstance>(new FileInstance(fd, 0)));
277 }
278}
279
Jorge E. Moreira6d7753e2018-07-18 11:28:48 -0700280SharedFD SharedFD::Creat(const char* path, mode_t mode) {
281 return SharedFD::Open(path, O_CREAT|O_WRONLY|O_TRUNC, mode);
282}
283
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700284SharedFD SharedFD::Socket(int domain, int socket_type, int protocol) {
285 int fd = TEMP_FAILURE_RETRY(socket(domain, socket_type, protocol));
286 if (fd == -1) {
287 return SharedFD(std::shared_ptr<FileInstance>(new FileInstance(fd, errno)));
288 } else {
289 return SharedFD(std::shared_ptr<FileInstance>(new FileInstance(fd, 0)));
290 }
291}
292
Cody Schuffelenfa69c382018-12-17 18:57:36 -0800293SharedFD SharedFD::ErrorFD(int error) {
294 return SharedFD(std::shared_ptr<FileInstance>(new FileInstance(-1, error)));
295}
296
Tomasz Wiszkowskid88403b2017-07-06 14:42:14 -0700297SharedFD SharedFD::SocketLocalClient(const char* name, bool abstract,
298 int in_type) {
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700299 struct sockaddr_un addr;
Ping-Hao Wu75cc1e02017-06-06 16:39:14 -0700300 socklen_t addrlen;
301 MakeAddress(name, abstract, &addr, &addrlen);
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700302 SharedFD rval = SharedFD::Socket(PF_UNIX, in_type, 0);
303 if (!rval->IsOpen()) {
304 return rval;
305 }
Ryan Haininge451e9d2018-05-09 17:02:32 -0700306 if (rval->Connect(reinterpret_cast<sockaddr*>(&addr), addrlen) == -1) {
Cody Schuffelenfa69c382018-12-17 18:57:36 -0800307 return SharedFD::ErrorFD(rval->GetErrno());
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700308 }
309 return rval;
310}
311
Ryan Hainingd5c1bde2018-01-29 13:34:22 -0800312SharedFD SharedFD::SocketLocalClient(int port, int type) {
313 sockaddr_in addr{};
314 addr.sin_family = AF_INET;
315 addr.sin_port = htons(port);
316 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
317 SharedFD rval = SharedFD::Socket(AF_INET, type, 0);
318 if (!rval->IsOpen()) {
319 return rval;
320 }
321 if (rval->Connect(reinterpret_cast<const sockaddr*>(&addr),
322 sizeof addr) < 0) {
Cody Schuffelenfa69c382018-12-17 18:57:36 -0800323 return SharedFD::ErrorFD(rval->GetErrno());
Ryan Hainingd5c1bde2018-01-29 13:34:22 -0800324 }
325 return rval;
326}
327
Jorge E. Moreira854bcbc2017-09-26 16:05:10 -0700328SharedFD SharedFD::SocketLocalServer(int port, int type) {
329 struct sockaddr_in addr;
330 memset(&addr, 0, sizeof(addr));
331 addr.sin_family = AF_INET;
332 addr.sin_port = htons(port);
333 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
334 SharedFD rval = SharedFD::Socket(AF_INET, type, 0);
335 if(!rval->IsOpen()) {
336 return rval;
337 }
338 int n = 1;
339 if (rval->SetSockOpt(SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)) == -1) {
340 LOG(ERROR) << "SetSockOpt failed " << rval->StrError();
Cody Schuffelenfa69c382018-12-17 18:57:36 -0800341 return SharedFD::ErrorFD(rval->GetErrno());
Jorge E. Moreira854bcbc2017-09-26 16:05:10 -0700342 }
Ryan Haininge451e9d2018-05-09 17:02:32 -0700343 if(rval->Bind(reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) < 0) {
Jorge E. Moreira854bcbc2017-09-26 16:05:10 -0700344 LOG(ERROR) << "Bind failed " << rval->StrError();
Cody Schuffelenfa69c382018-12-17 18:57:36 -0800345 return SharedFD::ErrorFD(rval->GetErrno());
Jorge E. Moreira854bcbc2017-09-26 16:05:10 -0700346 }
347 if (type == SOCK_STREAM) {
348 if (rval->Listen(4) < 0) {
349 LOG(ERROR) << "Listen failed " << rval->StrError();
Cody Schuffelenfa69c382018-12-17 18:57:36 -0800350 return SharedFD::ErrorFD(rval->GetErrno());
Jorge E. Moreira854bcbc2017-09-26 16:05:10 -0700351 }
352 }
353 return rval;
354}
355
Tomasz Wiszkowskid88403b2017-07-06 14:42:14 -0700356SharedFD SharedFD::SocketLocalServer(const char* name, bool abstract,
357 int in_type, mode_t mode) {
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700358 // DO NOT UNLINK addr.sun_path. It does NOT have to be null-terminated.
359 // See man 7 unix for more details.
360 if (!abstract) (void)unlink(name);
361
362 struct sockaddr_un addr;
Ping-Hao Wu75cc1e02017-06-06 16:39:14 -0700363 socklen_t addrlen;
364 MakeAddress(name, abstract, &addr, &addrlen);
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700365 SharedFD rval = SharedFD::Socket(PF_UNIX, in_type, 0);
366 if (!rval->IsOpen()) {
367 return rval;
368 }
369
370 int n = 1;
371 if (rval->SetSockOpt(SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)) == -1) {
372 LOG(ERROR) << "SetSockOpt failed " << rval->StrError();
Cody Schuffelenfa69c382018-12-17 18:57:36 -0800373 return SharedFD::ErrorFD(rval->GetErrno());
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700374 }
Ryan Haininge451e9d2018-05-09 17:02:32 -0700375 if (rval->Bind(reinterpret_cast<sockaddr*>(&addr), addrlen) == -1) {
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700376 LOG(ERROR) << "Bind failed; name=" << name << ": " << rval->StrError();
Cody Schuffelenfa69c382018-12-17 18:57:36 -0800377 return SharedFD::ErrorFD(rval->GetErrno());
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700378 }
379
380 /* Only the bottom bits are really the socket type; there are flags too. */
381 constexpr int SOCK_TYPE_MASK = 0xf;
382
383 // Connection oriented sockets: start listening.
384 if ((in_type & SOCK_TYPE_MASK) == SOCK_STREAM) {
385 // Follows the default from socket_local_server
386 if (rval->Listen(1) == -1) {
387 LOG(ERROR) << "Listen failed: " << rval->StrError();
Cody Schuffelenfa69c382018-12-17 18:57:36 -0800388 return SharedFD::ErrorFD(rval->GetErrno());
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700389 }
390 }
391
392 if (!abstract) {
393 if (TEMP_FAILURE_RETRY(chmod(name, mode)) == -1) {
394 LOG(ERROR) << "chmod failed: " << strerror(errno);
395 // However, continue since we do have a listening socket
396 }
397 }
398 return rval;
399}
400
Cody Schuffelenfa69c382018-12-17 18:57:36 -0800401SharedFD SharedFD::VsockServer(unsigned int port, int type) {
402 auto vsock = cvd::SharedFD::Socket(AF_VSOCK, type, 0);
403 if (!vsock->IsOpen()) {
404 return vsock;
405 }
406 sockaddr_vm addr{};
407 addr.svm_family = AF_VSOCK;
408 addr.svm_port = port;
409 addr.svm_cid = VMADDR_CID_ANY;
410 auto casted_addr = reinterpret_cast<sockaddr*>(&addr);
411 if (vsock->Bind(casted_addr, sizeof(addr)) == -1) {
412 LOG(ERROR) << "Bind failed (" << vsock->StrError() << ")";
413 return SharedFD::ErrorFD(vsock->GetErrno());
414 }
415 if (type == SOCK_STREAM) {
416 if (vsock->Listen(4) < 0) {
417 LOG(ERROR) << "Listen failed (" << vsock->StrError() << ")";
418 return SharedFD::ErrorFD(vsock->GetErrno());
419 }
420 }
421 return vsock;
422}
423
424SharedFD SharedFD::VsockClient(unsigned int cid, unsigned int port, int type) {
425 auto vsock = cvd::SharedFD::Socket(AF_VSOCK, type, 0);
426 if (!vsock->IsOpen()) {
427 return vsock;
428 }
429 sockaddr_vm addr{};
430 addr.svm_family = AF_VSOCK;
431 addr.svm_port = port;
432 addr.svm_cid = cid;
433 auto casted_addr = reinterpret_cast<sockaddr*>(&addr);
434 if (vsock->Connect(casted_addr, sizeof(addr)) == -1) {
Cody Schuffelenfa69c382018-12-17 18:57:36 -0800435 return SharedFD::ErrorFD(vsock->GetErrno());
436 }
437 return vsock;
438}
439
Greg Hartman153b1062017-11-11 12:09:21 -0800440} // namespace cvd