1 /*
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 <errno.h>
19 #include <fcntl.h>
20 #include <netinet/in.h>
21 #include <poll.h>
22 #include <sys/file.h>
23 #include <sys/mman.h>
24 #include <sys/stat.h>
25 #include <sys/syscall.h>
26 #include <sys/types.h>
27 #include <unistd.h>
28 #include <cstddef>
29
30 #include <algorithm>
31 #include <vector>
32
33 #include <android-base/logging.h>
34
35 #include "common/libs/fs/shared_buf.h"
36 #include "common/libs/fs/shared_select.h"
37
38 // #define ENABLE_GCE_SHARED_FD_LOGGING 1
39
40 namespace cuttlefish {
41
42 namespace {
43
MarkAll(const SharedFDSet & input,fd_set * dest,int * max_index)44 void MarkAll(const SharedFDSet& input, fd_set* dest, int* max_index) {
45 for (SharedFDSet::const_iterator it = input.begin(); it != input.end();
46 ++it) {
47 (*it)->Set(dest, max_index);
48 }
49 }
50
CheckMarked(fd_set * in_out_mask,SharedFDSet * in_out_set)51 void CheckMarked(fd_set* in_out_mask, SharedFDSet* in_out_set) {
52 if (!in_out_set) {
53 return;
54 }
55 SharedFDSet save;
56 save.swap(in_out_set);
57 for (SharedFDSet::iterator it = save.begin(); it != save.end(); ++it) {
58 if ((*it)->IsSet(in_out_mask)) {
59 in_out_set->Set(*it);
60 }
61 }
62 }
63
64 /*
65 * Android currently has host prebuilts of glibc 2.15 and 2.17, but
66 * memfd_create was only added in glibc 2.27. It was defined in Linux 3.17,
67 * so we consider it safe to use the low-level arbitrary syscall wrapper.
68 */
69 #ifndef __NR_memfd_create
70 # if defined(__x86_64__)
71 # define __NR_memfd_create 319
72 # elif defined(__i386__)
73 # define __NR_memfd_create 356
74 # elif defined(__aarch64__)
75 # define __NR_memfd_create 279
76 # else
77 /* No interest in other architectures. */
78 # error "Unknown architecture."
79 # endif
80 #endif
81
memfd_create_wrapper(const char * name,unsigned int flags)82 int memfd_create_wrapper(const char* name, unsigned int flags) {
83 #ifdef CUTTLEFISH_HOST
84 // TODO(schuffelen): Use memfd_create with a newer host libc.
85 return syscall(__NR_memfd_create, name, flags);
86 #else
87 return memfd_create(name, flags);
88 #endif
89 }
90
IsRegularFile(const int fd)91 bool IsRegularFile(const int fd) {
92 struct stat info;
93 if (fstat(fd, &info) < 0) {
94 return false;
95 }
96 return S_ISREG(info.st_mode);
97 }
98
99 constexpr size_t kPreferredBufferSize = 8192;
100
101 } // namespace
102
CopyFrom(FileInstance & in,size_t length)103 bool FileInstance::CopyFrom(FileInstance& in, size_t length) {
104 std::vector<char> buffer(kPreferredBufferSize);
105 while (length > 0) {
106 ssize_t num_read = in.Read(buffer.data(), std::min(buffer.size(), length));
107 if (num_read <= 0) {
108 return false;
109 }
110 length -= num_read;
111
112 ssize_t written = 0;
113 do {
114 auto res = Write(buffer.data(), num_read);
115 if (res <= 0) {
116 // The caller will have to log an appropriate message.
117 return false;
118 }
119 written += res;
120 } while(written < num_read);
121 }
122 return true;
123 }
124
CopyAllFrom(FileInstance & in)125 bool FileInstance::CopyAllFrom(FileInstance& in) {
126 // FileInstance may have been constructed with a non-zero errno_ value because
127 // the errno variable is not zeroed out before.
128 errno_ = 0;
129 in.errno_ = 0;
130 while (CopyFrom(in, kPreferredBufferSize)) {
131 }
132 // Only return false if there was an actual error.
133 return !GetErrno() && !in.GetErrno();
134 }
135
Close()136 void FileInstance::Close() {
137 std::stringstream message;
138 if (fd_ == -1) {
139 errno_ = EBADF;
140 } else if (close(fd_) == -1) {
141 errno_ = errno;
142 if (identity_.size()) {
143 message << __FUNCTION__ << ": " << identity_ << " failed (" << StrError() << ")";
144 std::string message_str = message.str();
145 Log(message_str.c_str());
146 }
147 } else {
148 if (identity_.size()) {
149 message << __FUNCTION__ << ": " << identity_ << "succeeded";
150 std::string message_str = message.str();
151 Log(message_str.c_str());
152 }
153 }
154 fd_ = -1;
155 }
156
Chmod(mode_t mode)157 bool FileInstance::Chmod(mode_t mode) {
158 int original_error = errno;
159 int ret = fchmod(fd_, mode);
160 if (ret != 0) {
161 errno_ = errno;
162 }
163 errno = original_error;
164 return ret == 0;
165 }
166
ConnectWithTimeout(const struct sockaddr * addr,socklen_t addrlen,struct timeval * timeout)167 int FileInstance::ConnectWithTimeout(const struct sockaddr* addr,
168 socklen_t addrlen,
169 struct timeval* timeout) {
170 int original_flags = Fcntl(F_GETFL, 0);
171 if (original_flags == -1) {
172 LOG(ERROR) << "Could not get current file descriptor flags: " << StrError();
173 return -1;
174 }
175 if (Fcntl(F_SETFL, original_flags | O_NONBLOCK) == -1) {
176 LOG(ERROR) << "Failed to set O_NONBLOCK: " << StrError();
177 return -1;
178 }
179
180 auto connect_res = Connect(
181 addr, addrlen); // This will return immediately because of O_NONBLOCK
182
183 if (connect_res == 0) { // Immediate success
184 if (Fcntl(F_SETFL, original_flags) == -1) {
185 LOG(ERROR) << "Failed to restore original flags: " << StrError();
186 return -1;
187 }
188 return 0;
189 }
190
191 if (GetErrno() != EAGAIN && GetErrno() != EINPROGRESS) {
192 LOG(DEBUG) << "Immediate connection failure: " << StrError();
193 if (Fcntl(F_SETFL, original_flags) == -1) {
194 LOG(ERROR) << "Failed to restore original flags: " << StrError();
195 }
196 return -1;
197 }
198
199 fd_set fdset;
200 FD_ZERO(&fdset);
201 FD_SET(fd_, &fdset);
202
203 int select_res = select(fd_ + 1, nullptr, &fdset, nullptr, timeout);
204
205 if (Fcntl(F_SETFL, original_flags) == -1) {
206 LOG(ERROR) << "Failed to restore original flags: " << StrError();
207 return -1;
208 }
209
210 if (select_res != 1) {
211 LOG(ERROR) << "Did not connect within the timeout";
212 return -1;
213 }
214
215 int so_error;
216 socklen_t len = sizeof(so_error);
217 if (GetSockOpt(SOL_SOCKET, SO_ERROR, &so_error, &len) == -1) {
218 LOG(ERROR) << "Failed to get socket options: " << StrError();
219 return -1;
220 }
221
222 if (so_error != 0) {
223 LOG(ERROR) << "Failure in opening socket: " << so_error;
224 errno_ = so_error;
225 return -1;
226 }
227 errno_ = 0;
228 return 0;
229 }
230
IsSet(fd_set * in) const231 bool FileInstance::IsSet(fd_set* in) const {
232 if (IsOpen() && FD_ISSET(fd_, in)) {
233 return true;
234 }
235 return false;
236 }
237
238 #if ENABLE_GCE_SHARED_FD_LOGGING
Log(const char * message)239 void FileInstance::Log(const char* message) {
240 LOG(INFO) << message;
241 }
242 #else
Log(const char *)243 void FileInstance::Log(const char*) {}
244 #endif
245
Set(fd_set * dest,int * max_index) const246 void FileInstance::Set(fd_set* dest, int* max_index) const {
247 if (!IsOpen()) {
248 return;
249 }
250 if (fd_ >= *max_index) {
251 *max_index = fd_ + 1;
252 }
253 FD_SET(fd_, dest);
254 }
255
Select(SharedFDSet * read_set,SharedFDSet * write_set,SharedFDSet * error_set,struct timeval * timeout)256 int Select(SharedFDSet* read_set, SharedFDSet* write_set,
257 SharedFDSet* error_set, struct timeval* timeout) {
258 int max_index = 0;
259 fd_set readfds;
260 FD_ZERO(&readfds);
261 if (read_set) {
262 MarkAll(*read_set, &readfds, &max_index);
263 }
264 fd_set writefds;
265 FD_ZERO(&writefds);
266 if (write_set) {
267 MarkAll(*write_set, &writefds, &max_index);
268 }
269 fd_set errorfds;
270 FD_ZERO(&errorfds);
271 if (error_set) {
272 MarkAll(*error_set, &errorfds, &max_index);
273 }
274
275 int rval = TEMP_FAILURE_RETRY(
276 select(max_index, &readfds, &writefds, &errorfds, timeout));
277 FileInstance::Log("select\n");
278 CheckMarked(&readfds, read_set);
279 CheckMarked(&writefds, write_set);
280 CheckMarked(&errorfds, error_set);
281 return rval;
282 }
283
Poll(std::vector<PollSharedFd> & fds,int timeout)284 int SharedFD::Poll(std::vector<PollSharedFd>& fds, int timeout) {
285 return Poll(fds.data(), fds.size(), timeout);
286 }
287
Poll(PollSharedFd * fds,size_t num_fds,int timeout)288 int SharedFD::Poll(PollSharedFd* fds, size_t num_fds, int timeout) {
289 std::vector<pollfd> native_pollfds(num_fds);
290 for (size_t i = 0; i < num_fds; i++) {
291 native_pollfds[i].fd = fds[i].fd->fd_;
292 native_pollfds[i].events = fds[i].events;
293 native_pollfds[i].revents = 0;
294 }
295 int ret = poll(native_pollfds.data(), native_pollfds.size(), timeout);
296 for (size_t i = 0; i < num_fds; i++) {
297 fds[i].revents = native_pollfds[i].revents;
298 }
299 return ret;
300 }
301
MakeAddress(const char * name,bool abstract,struct sockaddr_un * dest,socklen_t * len)302 static void MakeAddress(const char* name, bool abstract,
303 struct sockaddr_un* dest, socklen_t* len) {
304 memset(dest, 0, sizeof(*dest));
305 dest->sun_family = AF_UNIX;
306 // sun_path is NOT expected to be nul-terminated.
307 // See man 7 unix.
308 size_t namelen;
309 if (abstract) {
310 // ANDROID_SOCKET_NAMESPACE_ABSTRACT
311 namelen = strlen(name);
312 CHECK_LE(namelen, sizeof(dest->sun_path) - 1)
313 << "MakeAddress failed. Name=" << name << " is longer than allowed.";
314 dest->sun_path[0] = 0;
315 memcpy(dest->sun_path + 1, name, namelen);
316 } else {
317 // ANDROID_SOCKET_NAMESPACE_RESERVED
318 // ANDROID_SOCKET_NAMESPACE_FILESYSTEM
319 // TODO(pinghao): Distinguish between them?
320 namelen = strlen(name);
321 CHECK_LE(namelen, sizeof(dest->sun_path))
322 << "MakeAddress failed. Name=" << name << " is longer than allowed.";
323 strncpy(dest->sun_path, name, strlen(name));
324 }
325 *len = namelen + offsetof(struct sockaddr_un, sun_path) + 1;
326 }
327
Accept(const FileInstance & listener,struct sockaddr * addr,socklen_t * addrlen)328 SharedFD SharedFD::Accept(const FileInstance& listener, struct sockaddr* addr,
329 socklen_t* addrlen) {
330 return SharedFD(
331 std::shared_ptr<FileInstance>(listener.Accept(addr, addrlen)));
332 }
333
Accept(const FileInstance & listener)334 SharedFD SharedFD::Accept(const FileInstance& listener) {
335 return SharedFD::Accept(listener, NULL, NULL);
336 }
337
Dup(int unmanaged_fd)338 SharedFD SharedFD::Dup(int unmanaged_fd) {
339 int fd = fcntl(unmanaged_fd, F_DUPFD_CLOEXEC, 3);
340 int error_num = errno;
341 return SharedFD(std::shared_ptr<FileInstance>(new FileInstance(fd, error_num)));
342 }
343
Pipe(SharedFD * fd0,SharedFD * fd1)344 bool SharedFD::Pipe(SharedFD* fd0, SharedFD* fd1) {
345 int fds[2];
346 int rval = pipe(fds);
347 if (rval != -1) {
348 (*fd0) = std::shared_ptr<FileInstance>(new FileInstance(fds[0], errno));
349 (*fd1) = std::shared_ptr<FileInstance>(new FileInstance(fds[1], errno));
350 return true;
351 }
352 return false;
353 }
354
Event(int initval,int flags)355 SharedFD SharedFD::Event(int initval, int flags) {
356 int fd = eventfd(initval, flags);
357 return std::shared_ptr<FileInstance>(new FileInstance(fd, errno));
358 }
359
MemfdCreate(const std::string & name,unsigned int flags)360 SharedFD SharedFD::MemfdCreate(const std::string& name, unsigned int flags) {
361 int fd = memfd_create_wrapper(name.c_str(), flags);
362 int error_num = errno;
363 return std::shared_ptr<FileInstance>(new FileInstance(fd, error_num));
364 }
365
MemfdCreateWithData(const std::string & name,const std::string & data,unsigned int flags)366 SharedFD SharedFD::MemfdCreateWithData(const std::string& name, const std::string& data, unsigned int flags) {
367 auto memfd = MemfdCreate(name, flags);
368 if (WriteAll(memfd, data) != data.size()) {
369 return ErrorFD(errno);
370 }
371 if (memfd->LSeek(0, SEEK_SET) != 0) {
372 return ErrorFD(memfd->GetErrno());
373 }
374 if (!memfd->Chmod(0700)) {
375 return ErrorFD(memfd->GetErrno());
376 }
377 return memfd;
378 }
379
SocketPair(int domain,int type,int protocol,SharedFD * fd0,SharedFD * fd1)380 bool SharedFD::SocketPair(int domain, int type, int protocol,
381 SharedFD* fd0, SharedFD* fd1) {
382 int fds[2];
383 int rval = socketpair(domain, type, protocol, fds);
384 if (rval != -1) {
385 (*fd0) = std::shared_ptr<FileInstance>(new FileInstance(fds[0], errno));
386 (*fd1) = std::shared_ptr<FileInstance>(new FileInstance(fds[1], errno));
387 return true;
388 }
389 return false;
390 }
391
Open(const std::string & path,int flags,mode_t mode)392 SharedFD SharedFD::Open(const std::string& path, int flags, mode_t mode) {
393 int fd = TEMP_FAILURE_RETRY(open(path.c_str(), flags, mode));
394 if (fd == -1) {
395 return SharedFD(std::shared_ptr<FileInstance>(new FileInstance(fd, errno)));
396 } else {
397 return SharedFD(std::shared_ptr<FileInstance>(new FileInstance(fd, 0)));
398 }
399 }
400
Creat(const std::string & path,mode_t mode)401 SharedFD SharedFD::Creat(const std::string& path, mode_t mode) {
402 return SharedFD::Open(path, O_CREAT|O_WRONLY|O_TRUNC, mode);
403 }
404
Fchdir(SharedFD shared_fd)405 int SharedFD::Fchdir(SharedFD shared_fd) {
406 if (!shared_fd.value_) {
407 return -1;
408 }
409 errno = 0;
410 int rval = TEMP_FAILURE_RETRY(fchdir(shared_fd->fd_));
411 shared_fd->errno_ = errno;
412 return rval;
413 }
414
Fifo(const std::string & path,mode_t mode)415 SharedFD SharedFD::Fifo(const std::string& path, mode_t mode) {
416 struct stat st;
417 if (TEMP_FAILURE_RETRY(stat(path.c_str(), &st)) == 0) {
418 if (TEMP_FAILURE_RETRY(remove(path.c_str())) != 0) {
419 return ErrorFD(errno);
420 }
421 }
422
423 int fd = TEMP_FAILURE_RETRY(mkfifo(path.c_str(), mode));
424 if (fd == -1) {
425 return ErrorFD(errno);
426 }
427 return Open(path, mode);
428 }
429
Socket(int domain,int socket_type,int protocol)430 SharedFD SharedFD::Socket(int domain, int socket_type, int protocol) {
431 int fd = TEMP_FAILURE_RETRY(socket(domain, socket_type, protocol));
432 if (fd == -1) {
433 return SharedFD(std::shared_ptr<FileInstance>(new FileInstance(fd, errno)));
434 } else {
435 return SharedFD(std::shared_ptr<FileInstance>(new FileInstance(fd, 0)));
436 }
437 }
438
Mkstemp(std::string * path)439 SharedFD SharedFD::Mkstemp(std::string* path) {
440 int fd = mkstemp(path->data());
441 if (fd == -1) {
442 return SharedFD(std::shared_ptr<FileInstance>(new FileInstance(fd, errno)));
443 } else {
444 return SharedFD(std::shared_ptr<FileInstance>(new FileInstance(fd, 0)));
445 }
446 }
447
ErrorFD(int error)448 SharedFD SharedFD::ErrorFD(int error) {
449 return SharedFD(std::shared_ptr<FileInstance>(new FileInstance(-1, error)));
450 }
451
SocketLocalClient(const std::string & name,bool abstract,int in_type)452 SharedFD SharedFD::SocketLocalClient(const std::string& name, bool abstract,
453 int in_type) {
454 return SocketLocalClient(name, abstract, in_type, 0);
455 }
456
SocketLocalClient(const std::string & name,bool abstract,int in_type,int timeout_seconds)457 SharedFD SharedFD::SocketLocalClient(const std::string& name, bool abstract,
458 int in_type, int timeout_seconds) {
459 struct sockaddr_un addr;
460 socklen_t addrlen;
461 MakeAddress(name.c_str(), abstract, &addr, &addrlen);
462 SharedFD rval = SharedFD::Socket(PF_UNIX, in_type, 0);
463 if (!rval->IsOpen()) {
464 return rval;
465 }
466 struct timeval timeout = {timeout_seconds, 0};
467 auto casted_addr = reinterpret_cast<sockaddr*>(&addr);
468 if (rval->ConnectWithTimeout(casted_addr, addrlen, &timeout) == -1) {
469 return SharedFD::ErrorFD(rval->GetErrno());
470 }
471 return rval;
472 }
473
SocketLocalClient(int port,int type)474 SharedFD SharedFD::SocketLocalClient(int port, int type) {
475 sockaddr_in addr{};
476 addr.sin_family = AF_INET;
477 addr.sin_port = htons(port);
478 addr.sin_addr.s_addr = htonl(INADDR_ANY);
479 SharedFD rval = SharedFD::Socket(AF_INET, type, 0);
480 if (!rval->IsOpen()) {
481 return rval;
482 }
483 if (rval->Connect(reinterpret_cast<const sockaddr*>(&addr),
484 sizeof addr) < 0) {
485 return SharedFD::ErrorFD(rval->GetErrno());
486 }
487 return rval;
488 }
489
SocketLocalServer(int port,int type)490 SharedFD SharedFD::SocketLocalServer(int port, int type) {
491 struct sockaddr_in addr;
492 memset(&addr, 0, sizeof(addr));
493 addr.sin_family = AF_INET;
494 addr.sin_port = htons(port);
495 addr.sin_addr.s_addr = htonl(INADDR_ANY);
496 SharedFD rval = SharedFD::Socket(AF_INET, type, 0);
497 if(!rval->IsOpen()) {
498 return rval;
499 }
500 int n = 1;
501 if (rval->SetSockOpt(SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)) == -1) {
502 LOG(ERROR) << "SetSockOpt failed " << rval->StrError();
503 return SharedFD::ErrorFD(rval->GetErrno());
504 }
505 if(rval->Bind(reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) < 0) {
506 LOG(ERROR) << "Bind failed " << rval->StrError();
507 return SharedFD::ErrorFD(rval->GetErrno());
508 }
509 if (type == SOCK_STREAM || type == SOCK_SEQPACKET) {
510 if (rval->Listen(4) < 0) {
511 LOG(ERROR) << "Listen failed " << rval->StrError();
512 return SharedFD::ErrorFD(rval->GetErrno());
513 }
514 }
515 return rval;
516 }
517
SocketLocalServer(const std::string & name,bool abstract,int in_type,mode_t mode)518 SharedFD SharedFD::SocketLocalServer(const std::string& name, bool abstract,
519 int in_type, mode_t mode) {
520 // DO NOT UNLINK addr.sun_path. It does NOT have to be null-terminated.
521 // See man 7 unix for more details.
522 if (!abstract) (void)unlink(name.c_str());
523
524 struct sockaddr_un addr;
525 socklen_t addrlen;
526 MakeAddress(name.c_str(), abstract, &addr, &addrlen);
527 SharedFD rval = SharedFD::Socket(PF_UNIX, in_type, 0);
528 if (!rval->IsOpen()) {
529 return rval;
530 }
531
532 int n = 1;
533 if (rval->SetSockOpt(SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)) == -1) {
534 LOG(ERROR) << "SetSockOpt failed " << rval->StrError();
535 return SharedFD::ErrorFD(rval->GetErrno());
536 }
537 if (rval->Bind(reinterpret_cast<sockaddr*>(&addr), addrlen) == -1) {
538 LOG(ERROR) << "Bind failed; name=" << name << ": " << rval->StrError();
539 return SharedFD::ErrorFD(rval->GetErrno());
540 }
541
542 /* Only the bottom bits are really the socket type; there are flags too. */
543 constexpr int SOCK_TYPE_MASK = 0xf;
544 auto socket_type = in_type & SOCK_TYPE_MASK;
545
546 // Connection oriented sockets: start listening.
547 if (socket_type == SOCK_STREAM || socket_type == SOCK_SEQPACKET) {
548 // Follows the default from socket_local_server
549 if (rval->Listen(1) == -1) {
550 LOG(ERROR) << "Listen failed: " << rval->StrError();
551 return SharedFD::ErrorFD(rval->GetErrno());
552 }
553 }
554
555 if (!abstract) {
556 if (TEMP_FAILURE_RETRY(chmod(name.c_str(), mode)) == -1) {
557 LOG(ERROR) << "chmod failed: " << strerror(errno);
558 // However, continue since we do have a listening socket
559 }
560 }
561 return rval;
562 }
563
VsockServer(unsigned int port,int type,unsigned int cid)564 SharedFD SharedFD::VsockServer(unsigned int port, int type, unsigned int cid) {
565 auto vsock = SharedFD::Socket(AF_VSOCK, type, 0);
566 if (!vsock->IsOpen()) {
567 return vsock;
568 }
569 sockaddr_vm addr{};
570 addr.svm_family = AF_VSOCK;
571 addr.svm_port = port;
572 addr.svm_cid = cid;
573 auto casted_addr = reinterpret_cast<sockaddr*>(&addr);
574 if (vsock->Bind(casted_addr, sizeof(addr)) == -1) {
575 LOG(ERROR) << "Port " << port << " Bind failed (" << vsock->StrError()
576 << ")";
577 return SharedFD::ErrorFD(vsock->GetErrno());
578 }
579 if (type == SOCK_STREAM || type == SOCK_SEQPACKET) {
580 if (vsock->Listen(4) < 0) {
581 LOG(ERROR) << "Port" << port << " Listen failed (" << vsock->StrError()
582 << ")";
583 return SharedFD::ErrorFD(vsock->GetErrno());
584 }
585 }
586 return vsock;
587 }
588
VsockServer(int type)589 SharedFD SharedFD::VsockServer(int type) {
590 return VsockServer(VMADDR_PORT_ANY, type);
591 }
592
VsockClient(unsigned int cid,unsigned int port,int type)593 SharedFD SharedFD::VsockClient(unsigned int cid, unsigned int port, int type) {
594 auto vsock = SharedFD::Socket(AF_VSOCK, type, 0);
595 if (!vsock->IsOpen()) {
596 return vsock;
597 }
598 sockaddr_vm addr{};
599 addr.svm_family = AF_VSOCK;
600 addr.svm_port = port;
601 addr.svm_cid = cid;
602 auto casted_addr = reinterpret_cast<sockaddr*>(&addr);
603 if (vsock->Connect(casted_addr, sizeof(addr)) == -1) {
604 return SharedFD::ErrorFD(vsock->GetErrno());
605 }
606 return vsock;
607 }
608
lock() const609 SharedFD WeakFD::lock() const {
610 auto locked_file_instance = value_.lock();
611 if (locked_file_instance) {
612 return SharedFD(locked_file_instance);
613 }
614 return SharedFD();
615 }
616
ScopedMMap(void * ptr,size_t len)617 ScopedMMap::ScopedMMap(void* ptr, size_t len) : ptr_(ptr), len_(len) {}
618
ScopedMMap()619 ScopedMMap::ScopedMMap() : ptr_(MAP_FAILED), len_(0) {}
620
ScopedMMap(ScopedMMap && other)621 ScopedMMap::ScopedMMap(ScopedMMap&& other)
622 : ptr_(other.ptr_), len_(other.len_) {
623 other.ptr_ = MAP_FAILED;
624 other.len_ = 0;
625 }
626
~ScopedMMap()627 ScopedMMap::~ScopedMMap() {
628 if (ptr_ != MAP_FAILED) {
629 munmap(ptr_, len_);
630 }
631 }
632
ClosedInstance()633 /* static */ std::shared_ptr<FileInstance> FileInstance::ClosedInstance() {
634 return std::shared_ptr<FileInstance>(new FileInstance(-1, EBADF));
635 }
636
Bind(const struct sockaddr * addr,socklen_t addrlen)637 int FileInstance::Bind(const struct sockaddr* addr, socklen_t addrlen) {
638 errno = 0;
639 int rval = bind(fd_, addr, addrlen);
640 errno_ = errno;
641 return rval;
642 }
643
Connect(const struct sockaddr * addr,socklen_t addrlen)644 int FileInstance::Connect(const struct sockaddr* addr, socklen_t addrlen) {
645 errno = 0;
646 int rval = connect(fd_, addr, addrlen);
647 errno_ = errno;
648 return rval;
649 }
650
UNMANAGED_Dup()651 int FileInstance::UNMANAGED_Dup() {
652 errno = 0;
653 int rval = TEMP_FAILURE_RETRY(dup(fd_));
654 errno_ = errno;
655 return rval;
656 }
657
UNMANAGED_Dup2(int newfd)658 int FileInstance::UNMANAGED_Dup2(int newfd) {
659 errno = 0;
660 int rval = TEMP_FAILURE_RETRY(dup2(fd_, newfd));
661 errno_ = errno;
662 return rval;
663 }
664
Fcntl(int command,int value)665 int FileInstance::Fcntl(int command, int value) {
666 errno = 0;
667 int rval = TEMP_FAILURE_RETRY(fcntl(fd_, command, value));
668 errno_ = errno;
669 return rval;
670 }
671
Flock(int operation)672 int FileInstance::Flock(int operation) {
673 errno = 0;
674 int rval = TEMP_FAILURE_RETRY(flock(fd_, operation));
675 errno_ = errno;
676 return rval;
677 }
678
GetSockName(struct sockaddr * addr,socklen_t * addrlen)679 int FileInstance::GetSockName(struct sockaddr* addr, socklen_t* addrlen) {
680 errno = 0;
681 int rval = TEMP_FAILURE_RETRY(getsockname(fd_, addr, addrlen));
682 if (rval == -1) {
683 errno_ = errno;
684 }
685 return rval;
686 }
687
VsockServerPort()688 unsigned int FileInstance::VsockServerPort() {
689 struct sockaddr_vm vm_socket;
690 socklen_t length = sizeof(vm_socket);
691 GetSockName(reinterpret_cast<struct sockaddr*>(&vm_socket), &length);
692 return vm_socket.svm_port;
693 }
694
Ioctl(int request,void * val)695 int FileInstance::Ioctl(int request, void* val) {
696 errno = 0;
697 int rval = TEMP_FAILURE_RETRY(ioctl(fd_, request, val));
698 errno_ = errno;
699 return rval;
700 }
701
LinkAtCwd(const std::string & path)702 int FileInstance::LinkAtCwd(const std::string& path) {
703 std::string name = "/proc/self/fd/";
704 name += std::to_string(fd_);
705 errno = 0;
706 int rval =
707 linkat(-1, name.c_str(), AT_FDCWD, path.c_str(), AT_SYMLINK_FOLLOW);
708 errno_ = errno;
709 return rval;
710 }
711
Listen(int backlog)712 int FileInstance::Listen(int backlog) {
713 errno = 0;
714 int rval = listen(fd_, backlog);
715 errno_ = errno;
716 return rval;
717 }
718
LSeek(off_t offset,int whence)719 off_t FileInstance::LSeek(off_t offset, int whence) {
720 errno = 0;
721 off_t rval = TEMP_FAILURE_RETRY(lseek(fd_, offset, whence));
722 errno_ = errno;
723 return rval;
724 }
725
Recv(void * buf,size_t len,int flags)726 ssize_t FileInstance::Recv(void* buf, size_t len, int flags) {
727 errno = 0;
728 ssize_t rval = TEMP_FAILURE_RETRY(recv(fd_, buf, len, flags));
729 errno_ = errno;
730 return rval;
731 }
732
RecvMsg(struct msghdr * msg,int flags)733 ssize_t FileInstance::RecvMsg(struct msghdr* msg, int flags) {
734 errno = 0;
735 ssize_t rval = TEMP_FAILURE_RETRY(recvmsg(fd_, msg, flags));
736 errno_ = errno;
737 return rval;
738 }
739
Read(void * buf,size_t count)740 ssize_t FileInstance::Read(void* buf, size_t count) {
741 errno = 0;
742 ssize_t rval = TEMP_FAILURE_RETRY(read(fd_, buf, count));
743 errno_ = errno;
744 return rval;
745 }
746
EventfdRead(eventfd_t * value)747 int FileInstance::EventfdRead(eventfd_t* value) {
748 errno = 0;
749 auto rval = eventfd_read(fd_, value);
750 errno_ = errno;
751 return rval;
752 }
753
Send(const void * buf,size_t len,int flags)754 ssize_t FileInstance::Send(const void* buf, size_t len, int flags) {
755 errno = 0;
756 ssize_t rval = TEMP_FAILURE_RETRY(send(fd_, buf, len, flags));
757 errno_ = errno;
758 return rval;
759 }
760
SendMsg(const struct msghdr * msg,int flags)761 ssize_t FileInstance::SendMsg(const struct msghdr* msg, int flags) {
762 errno = 0;
763 ssize_t rval = TEMP_FAILURE_RETRY(sendmsg(fd_, msg, flags));
764 errno_ = errno;
765 return rval;
766 }
767
Shutdown(int how)768 int FileInstance::Shutdown(int how) {
769 errno = 0;
770 int rval = shutdown(fd_, how);
771 errno_ = errno;
772 return rval;
773 }
774
SetSockOpt(int level,int optname,const void * optval,socklen_t optlen)775 int FileInstance::SetSockOpt(int level, int optname, const void* optval,
776 socklen_t optlen) {
777 errno = 0;
778 int rval = setsockopt(fd_, level, optname, optval, optlen);
779 errno_ = errno;
780 return rval;
781 }
782
GetSockOpt(int level,int optname,void * optval,socklen_t * optlen)783 int FileInstance::GetSockOpt(int level, int optname, void* optval,
784 socklen_t* optlen) {
785 errno = 0;
786 int rval = getsockopt(fd_, level, optname, optval, optlen);
787 errno_ = errno;
788 return rval;
789 }
790
SetTerminalRaw()791 int FileInstance::SetTerminalRaw() {
792 errno = 0;
793 termios terminal_settings;
794 int rval = tcgetattr(fd_, &terminal_settings);
795 errno_ = errno;
796 if (rval < 0) {
797 return rval;
798 }
799 cfmakeraw(&terminal_settings);
800 rval = tcsetattr(fd_, TCSANOW, &terminal_settings);
801 errno_ = errno;
802 return rval;
803 }
804
StrError() const805 std::string FileInstance::StrError() const {
806 errno = 0;
807 return std::string(strerror(errno_));
808 }
809
MMap(void * addr,size_t length,int prot,int flags,off_t offset)810 ScopedMMap FileInstance::MMap(void* addr, size_t length, int prot, int flags,
811 off_t offset) {
812 errno = 0;
813 auto ptr = mmap(addr, length, prot, flags, fd_, offset);
814 errno_ = errno;
815 return ScopedMMap(ptr, length);
816 }
817
Truncate(off_t length)818 ssize_t FileInstance::Truncate(off_t length) {
819 errno = 0;
820 ssize_t rval = TEMP_FAILURE_RETRY(ftruncate(fd_, length));
821 errno_ = errno;
822 return rval;
823 }
824
Write(const void * buf,size_t count)825 ssize_t FileInstance::Write(const void* buf, size_t count) {
826 if (count == 0 && !IsRegular()) {
827 return 0;
828 }
829 errno = 0;
830 ssize_t rval = TEMP_FAILURE_RETRY(write(fd_, buf, count));
831 errno_ = errno;
832 return rval;
833 }
834
EventfdWrite(eventfd_t value)835 int FileInstance::EventfdWrite(eventfd_t value) {
836 errno = 0;
837 int rval = eventfd_write(fd_, value);
838 errno_ = errno;
839 return rval;
840 }
841
IsATTY()842 bool FileInstance::IsATTY() {
843 errno = 0;
844 int rval = isatty(fd_);
845 errno_ = errno;
846 return rval;
847 }
848
FileInstance(int fd,int in_errno)849 FileInstance::FileInstance(int fd, int in_errno)
850 : fd_(fd), errno_(in_errno), is_regular_file_(IsRegularFile(fd_)) {
851 // Ensure every file descriptor managed by a FileInstance has the CLOEXEC
852 // flag
853 TEMP_FAILURE_RETRY(fcntl(fd, F_SETFD, FD_CLOEXEC));
854 std::stringstream identity;
855 identity << "fd=" << fd << " @" << this;
856 identity_ = identity.str();
857 }
858
Accept(struct sockaddr * addr,socklen_t * addrlen) const859 FileInstance* FileInstance::Accept(struct sockaddr* addr,
860 socklen_t* addrlen) const {
861 int fd = TEMP_FAILURE_RETRY(accept(fd_, addr, addrlen));
862 if (fd == -1) {
863 return new FileInstance(fd, errno);
864 } else {
865 return new FileInstance(fd, 0);
866 }
867 }
868
869 } // namespace cuttlefish
870