blob: 044c7cc1fded0bbe76b472c6865f206d73a3bb69 [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 */
Greg Hartman3c95aac2017-06-14 18:24:26 -070016
17// TODO: We can't use std::shared_ptr on the older guests due to HALs.
18
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -070019#ifndef CUTTLEFISH_COMMON_COMMON_LIBS_FS_SHARED_FD_H_
20#define CUTTLEFISH_COMMON_COMMON_LIBS_FS_SHARED_FD_H_
21
Tomasz Wiszkowski16fb1742017-09-15 14:31:53 -070022#include <sys/epoll.h>
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -070023#include <sys/eventfd.h>
24#include <sys/ioctl.h>
Greg Hartman40b88f52017-06-22 15:34:11 -070025#include <sys/mman.h>
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -070026#include <sys/select.h>
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -070027#include <sys/socket.h>
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -070028#include <sys/types.h>
29#include <sys/stat.h>
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -070030#include <sys/time.h>
Tomasz Wiszkowskiaf38c7c2017-08-14 12:33:11 -070031#include <sys/timerfd.h>
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -070032#include <sys/uio.h>
33#include <sys/un.h>
34
35#include <memory>
Cody Schuffelen4ede79d2019-11-13 13:24:12 -080036#include <sstream>
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -070037
38#include <errno.h>
39#include <fcntl.h>
40#include <string.h>
41#include <unistd.h>
42
Cody Schuffelenfa69c382018-12-17 18:57:36 -080043#include "vm_sockets.h"
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -070044
45/**
46 * Classes to to enable safe access to files.
47 * POSIX kernels have an unfortunate habit of recycling file descriptors.
48 * That can cause problems like http://b/26121457 in code that doesn't manage
49 * file lifetimes properly. These classes implement an alternate interface
50 * that has some advantages:
51 *
52 * o References to files are tightly controlled
53 * o Files are auto-closed if they go out of scope
54 * o Files are life-time aware. It is impossible to close the instance twice.
55 * o File descriptors are always initialized. By default the descriptor is
56 * set to a closed instance.
57 *
58 * These classes are designed to mimic to POSIX interface as closely as
59 * possible. Specifically, they don't attempt to track the type of file
60 * descriptors and expose only the valid operations. This is by design, since
61 * it makes it easier to convert existing code to SharedFDs and avoids the
62 * possibility that new POSIX functionality will lead to large refactorings.
63 */
Greg Hartman153b1062017-11-11 12:09:21 -080064namespace cvd {
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -070065
66class FileInstance;
67
68/**
Greg Hartman3c95aac2017-06-14 18:24:26 -070069 * Describes the fields in msghdr that are honored by the *MsgAndFDs
70 * calls.
71 */
72struct InbandMessageHeader {
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -070073 void* msg_name;
74 socklen_t msg_namelen;
Greg Hartman3c95aac2017-06-14 18:24:26 -070075 struct iovec* msg_iov;
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -070076 size_t msg_iovlen;
77 int msg_flags;
Greg Hartman3c95aac2017-06-14 18:24:26 -070078
79 void Convert(struct msghdr* dest) const {
80 dest->msg_name = msg_name;
81 dest->msg_namelen = msg_namelen;
82 dest->msg_iov = msg_iov;
83 dest->msg_iovlen = msg_iovlen;
84 dest->msg_flags = msg_flags;
85 }
86};
87
88/**
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -070089 * Counted reference to a FileInstance.
90 *
91 * This is also the place where most new FileInstances are created. The creation
92 * mehtods correspond to the underlying POSIX calls.
93 *
94 * SharedFDs can be compared and stored in STL containers. The semantics are
95 * slightly different from POSIX file descriptors:
96 *
97 * o The value of the SharedFD is the identity of its underlying FileInstance.
98 *
99 * o Each newly created SharedFD has a unique, closed FileInstance:
100 * SharedFD a, b;
101 * assert (a != b);
102 * a = b;
103 * asssert(a == b);
104 *
105 * o The identity of the FileInstance is not affected by closing the file:
106 * SharedFD a, b;
107 * set<SharedFD> s;
108 * s.insert(a);
109 * assert(s.count(a) == 1);
110 * assert(s.count(b) == 0);
111 * a->Close();
112 * assert(s.count(a) == 1);
113 * assert(s.count(b) == 0);
114 *
115 * o FileInstances are never visibly recycled.
116 *
117 * o If all of the SharedFDs referring to a FileInstance go out of scope the
118 * file is closed and the FileInstance is recycled.
119 *
120 * Creation methods must ensure that no references to the new file descriptor
121 * escape. The underlying FileInstance should have the only reference to the
122 * file descriptor. Any method that needs to know the fd must be in either
123 * SharedFD or FileInstance.
124 *
125 * SharedFDs always have an underlying FileInstance, so all of the method
126 * calls are safe in accordance with the null object pattern.
127 *
128 * Errors on system calls that create new FileInstances, such as Open, are
129 * reported with a new, closed FileInstance with the errno set.
130 */
131class SharedFD {
132 public:
133 inline SharedFD();
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700134 SharedFD(const std::shared_ptr<FileInstance>& in) : value_(in) {}
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700135 // Reference the listener as a FileInstance to make this FD type agnostic.
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700136 static SharedFD Accept(const FileInstance& listener, struct sockaddr* addr,
137 socklen_t* addrlen);
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700138 static SharedFD Accept(const FileInstance& listener);
Greg Hartman3c95aac2017-06-14 18:24:26 -0700139 static SharedFD Dup(int unmanaged_fd);
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700140 static SharedFD GetControlSocket(const char* name);
Jorge E. Moreira6ffa0cb2018-10-24 17:19:39 -0700141 // All SharedFDs have the O_CLOEXEC flag after creation. To remove use the
142 // Fcntl or Dup functions.
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700143 static SharedFD Open(const char* pathname, int flags, mode_t mode = 0);
Jorge E. Moreira6d7753e2018-07-18 11:28:48 -0700144 static SharedFD Creat(const char* pathname, mode_t mode);
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700145 static bool Pipe(SharedFD* fd0, SharedFD* fd1);
Tomasz Wiszkowskid88403b2017-07-06 14:42:14 -0700146 static SharedFD Event(int initval = 0, int flags = 0);
Tomasz Wiszkowski16fb1742017-09-15 14:31:53 -0700147 static SharedFD Epoll(int flags = 0);
Cody Schuffelen2a4746f2019-08-28 12:46:45 -0700148 static SharedFD MemfdCreate(const char* name, unsigned int flags = 0);
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700149 static bool SocketPair(int domain, int type, int protocol, SharedFD* fd0,
150 SharedFD* fd1);
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700151 static SharedFD Socket(int domain, int socket_type, int protocol);
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700152 static SharedFD SocketLocalClient(const char* name, bool is_abstract,
153 int in_type);
Ryan Hainingd5c1bde2018-01-29 13:34:22 -0800154 static SharedFD SocketLocalClient(int port, int type);
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700155 static SharedFD SocketLocalServer(const char* name, bool is_abstract,
156 int in_type, mode_t mode);
Jorge E. Moreira854bcbc2017-09-26 16:05:10 -0700157 static SharedFD SocketLocalServer(int port, int type);
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700158 static SharedFD SocketSeqPacketServer(const char* name, mode_t mode);
159 static SharedFD SocketSeqPacketClient(const char* name);
Cody Schuffelenfa69c382018-12-17 18:57:36 -0800160 static SharedFD VsockServer(unsigned int port, int type);
Cody Schuffelen14ecb072019-11-26 17:59:33 -0800161 static SharedFD VsockServer(int type);
Cody Schuffelenfa69c382018-12-17 18:57:36 -0800162 static SharedFD VsockClient(unsigned int cid, unsigned int port, int type);
Tomasz Wiszkowskiaf38c7c2017-08-14 12:33:11 -0700163 static SharedFD TimerFD(int clock, int flags);
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700164
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700165 bool operator==(const SharedFD& rhs) const { return value_ == rhs.value_; }
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700166
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700167 bool operator!=(const SharedFD& rhs) const { return value_ != rhs.value_; }
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700168
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700169 bool operator<(const SharedFD& rhs) const { return value_ < rhs.value_; }
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700170
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700171 bool operator<=(const SharedFD& rhs) const { return value_ <= rhs.value_; }
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700172
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700173 bool operator>(const SharedFD& rhs) const { return value_ > rhs.value_; }
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700174
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700175 bool operator>=(const SharedFD& rhs) const { return value_ >= rhs.value_; }
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700176
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700177 std::shared_ptr<FileInstance> operator->() const { return value_; }
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700178
Greg Hartman153b1062017-11-11 12:09:21 -0800179 const cvd::FileInstance& operator*() const { return *value_; }
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700180
Greg Hartman153b1062017-11-11 12:09:21 -0800181 cvd::FileInstance& operator*() { return *value_; }
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700182
183 private:
Cody Schuffelenfa69c382018-12-17 18:57:36 -0800184 static SharedFD ErrorFD(int error);
185
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700186 std::shared_ptr<FileInstance> value_;
187};
188
189/**
190 * Tracks the lifetime of a file descriptor and provides methods to allow
191 * callers to use the file without knowledge of the underlying descriptor
192 * number.
193 *
194 * FileInstances have two states: Open and Closed. They may start in either
195 * state. However, once a FileIntance enters the Closed state it cannot be
196 * reopened.
197 *
198 * Construction of FileInstances is limited to select classes to avoid
199 * escaping file descriptors. At this point SharedFD is the only class
200 * that has access. We may eventually have ScopedFD and WeakFD.
201 */
202class FileInstance {
203 // Give SharedFD access to the aliasing constructor.
204 friend class SharedFD;
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700205
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700206 public:
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700207 virtual ~FileInstance() { Close(); }
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700208
209 // This can't be a singleton because our shared_ptr's aren't thread safe.
210 static std::shared_ptr<FileInstance> ClosedInstance() {
211 return std::shared_ptr<FileInstance>(new FileInstance(-1, EBADF));
212 }
213
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700214 int Bind(const struct sockaddr* addr, socklen_t addrlen) {
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700215 errno = 0;
216 int rval = bind(fd_, addr, addrlen);
217 errno_ = errno;
218 return rval;
219 }
220
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700221 int Connect(const struct sockaddr* addr, socklen_t addrlen) {
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700222 errno = 0;
223 int rval = connect(fd_, addr, addrlen);
224 errno_ = errno;
225 return rval;
226 }
227
228 void Close();
229
230 // Returns true if the entire input was copied.
231 // Otherwise an error will be set either on this file or the input.
232 // The non-const reference is needed to avoid binding this to a particular
233 // reference type.
234 bool CopyFrom(FileInstance& in);
Jorge E. Moreiracfbb4102018-07-02 18:53:24 -0700235 bool CopyFrom(FileInstance& in, size_t length);
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700236
237 int UNMANAGED_Dup() {
238 errno = 0;
239 int rval = TEMP_FAILURE_RETRY(dup(fd_));
240 errno_ = errno;
241 return rval;
242 }
243
Jorge E. Moreira6d7753e2018-07-18 11:28:48 -0700244 int UNMANAGED_Dup2(int newfd) {
245 errno = 0;
246 int rval = TEMP_FAILURE_RETRY(dup2(fd_, newfd));
247 errno_ = errno;
248 return rval;
249 }
250
Greg Hartman153b1062017-11-11 12:09:21 -0800251 int EpollCtl(int op, cvd::SharedFD new_fd, struct epoll_event* event) {
Tomasz Wiszkowski16fb1742017-09-15 14:31:53 -0700252 errno = 0;
Greg Hartmand0f20d42017-12-19 23:47:26 -0800253 int rval = TEMP_FAILURE_RETRY(epoll_ctl(fd_, op, new_fd->fd_, event));
Tomasz Wiszkowski16fb1742017-09-15 14:31:53 -0700254 errno_ = errno;
255 return rval;
256 }
257
258 int EpollWait(struct epoll_event* events, int maxevents, int timeout) {
259 errno = 0;
Greg Hartmand0f20d42017-12-19 23:47:26 -0800260 int rval = TEMP_FAILURE_RETRY(epoll_wait(fd_, events, maxevents, timeout));
Tomasz Wiszkowski16fb1742017-09-15 14:31:53 -0700261 errno_ = errno;
262 return rval;
263 }
264
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700265 int Fchown(uid_t owner, gid_t group) {
266 errno = 0;
267 int rval = TEMP_FAILURE_RETRY(fchown(fd_, owner, group));
268 errno_ = errno;
269 return rval;
270 }
271
272 int Fcntl(int command, int value) {
273 errno = 0;
274 int rval = TEMP_FAILURE_RETRY(fcntl(fd_, command, value));
275 errno_ = errno;
276 return rval;
277 }
278
279 int Fstat(struct stat* buf) {
280 errno = 0;
281 int rval = TEMP_FAILURE_RETRY(fstat(fd_, buf));
282 errno_ = errno;
283 return rval;
284 }
285
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700286 int GetErrno() const { return errno_; }
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700287
288 int GetSockOpt(int level, int optname, void* optval, socklen_t* optlen) {
289 errno = 0;
290 int rval = getsockopt(fd_, level, optname, optval, optlen);
291 if (rval == -1) {
292 errno_ = errno;
293 }
294 return rval;
295 }
296
Cody Schuffelen14ecb072019-11-26 17:59:33 -0800297 int GetSockName(struct sockaddr* addr, socklen_t* addrlen) {
298 errno = 0;
299 int rval = TEMP_FAILURE_RETRY(getsockname(fd_, addr, addrlen));
300 if (rval == -1) {
301 errno_ = errno;
302 }
303 return rval;
304 }
305
306 unsigned int VsockServerPort() {
307 struct sockaddr_vm vm_socket;
308 socklen_t length = sizeof(vm_socket);
309 GetSockName(reinterpret_cast<struct sockaddr*>(&vm_socket), &length);
310 return vm_socket.svm_port;
311 }
312
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700313 void Identify(const char* identity);
314
Greg Hartman40b88f52017-06-22 15:34:11 -0700315 int Ioctl(int request, void* val = nullptr) {
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700316 errno = 0;
Greg Hartman40b88f52017-06-22 15:34:11 -0700317 int rval = TEMP_FAILURE_RETRY(ioctl(fd_, request, val));
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700318 errno_ = errno;
319 return rval;
320 }
321
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700322 bool IsOpen() const { return fd_ != -1; }
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700323
324 // in probably isn't modified, but the API spec doesn't have const.
325 bool IsSet(fd_set* in) const;
326
327 int Listen(int backlog) {
328 errno = 0;
329 int rval = listen(fd_, backlog);
330 errno_ = errno;
331 return rval;
332 }
333
334 static void Log(const char* message);
335
336 off_t LSeek(off_t offset, int whence) {
337 errno = 0;
338 off_t rval = TEMP_FAILURE_RETRY(lseek(fd_, offset, whence));
339 errno_ = errno;
340 return rval;
341 }
342
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700343 void* Mmap(void* addr, size_t length, int prot, int flags, off_t offset) {
Greg Hartman40b88f52017-06-22 15:34:11 -0700344 errno = 0;
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700345 void* rval = mmap(addr, length, prot, flags, fd_, offset);
Greg Hartman40b88f52017-06-22 15:34:11 -0700346 errno_ = errno;
347 return rval;
348 }
349
350 ssize_t Pread(void* buf, size_t count, off_t offset) {
351 errno = 0;
352 ssize_t rval = TEMP_FAILURE_RETRY(pread(fd_, buf, count, offset));
353 errno_ = errno;
354 return rval;
355 }
356
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700357 ssize_t Recv(void* buf, size_t len, int flags) {
358 errno = 0;
359 ssize_t rval = TEMP_FAILURE_RETRY(recv(fd_, buf, len, flags));
360 errno_ = errno;
361 return rval;
362 }
363
364 ssize_t RecvFrom(void* buf, size_t len, int flags, struct sockaddr* src_addr,
365 socklen_t* addr_len) {
366 errno = 0;
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700367 ssize_t rval =
368 TEMP_FAILURE_RETRY(recvfrom(fd_, buf, len, flags, src_addr, addr_len));
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700369 errno_ = errno;
370 return rval;
371 }
372
373 ssize_t RecvMsg(struct msghdr* msg, int flags) {
374 errno = 0;
375 ssize_t rval = TEMP_FAILURE_RETRY(recvmsg(fd_, msg, flags));
376 errno_ = errno;
377 return rval;
378 }
379
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700380 template <size_t SZ>
381 ssize_t RecvMsgAndFDs(const struct InbandMessageHeader& msg_in, int flags,
382 SharedFD (*new_fds)[SZ]) {
Greg Hartman3c95aac2017-06-14 18:24:26 -0700383 // We need to make some modifications to land the fds. Make it clear
384 // that there are no updates to the msg being passed in during this call.
385 struct msghdr msg;
386 msg_in.Convert(&msg);
387 union {
388 char buffer[CMSG_SPACE(SZ * sizeof(int))];
389 struct cmsghdr this_aligns_buffer;
390 } u;
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700391 msg.msg_control = u.buffer;
Greg Hartman3c95aac2017-06-14 18:24:26 -0700392 msg.msg_controllen = sizeof(u.buffer);
393
394 cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700395 cmsg->cmsg_len = CMSG_LEN(SZ * sizeof(int));
Greg Hartman3c95aac2017-06-14 18:24:26 -0700396 cmsg->cmsg_level = SOL_SOCKET;
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700397 cmsg->cmsg_type = SCM_RIGHTS;
Greg Hartman3c95aac2017-06-14 18:24:26 -0700398 int* fd_array = reinterpret_cast<int*>(CMSG_DATA(cmsg));
Greg Hartmanee76f042017-12-04 18:33:51 -0800399 for (size_t i = 0; i < SZ; ++i) {
Greg Hartman3c95aac2017-06-14 18:24:26 -0700400 fd_array[i] = -1;
401 }
402 ssize_t rval = RecvMsg(&msg, flags);
Greg Hartmanee76f042017-12-04 18:33:51 -0800403 for (size_t i = 0; i < SZ; ++i) {
Greg Hartman3c95aac2017-06-14 18:24:26 -0700404 (*new_fds)[i] =
405 std::shared_ptr<FileInstance>(new FileInstance(fd_array[i], errno));
406 }
407 return rval;
408 }
409
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700410 ssize_t Read(void* buf, size_t count) {
411 errno = 0;
412 ssize_t rval = TEMP_FAILURE_RETRY(read(fd_, buf, count));
413 errno_ = errno;
414 return rval;
415 }
416
417 ssize_t Send(const void* buf, size_t len, int flags) {
418 errno = 0;
419 ssize_t rval = TEMP_FAILURE_RETRY(send(fd_, buf, len, flags));
420 errno_ = errno;
421 return rval;
422 }
423
424 ssize_t SendMsg(const struct msghdr* msg, int flags) {
425 errno = 0;
426 ssize_t rval = TEMP_FAILURE_RETRY(sendmsg(fd_, msg, flags));
427 errno_ = errno;
428 return rval;
429 }
430
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700431 template <size_t SZ>
432 ssize_t SendMsgAndFDs(const struct InbandMessageHeader& msg_in, int flags,
433 const SharedFD (&fds)[SZ]) {
Greg Hartman3c95aac2017-06-14 18:24:26 -0700434 struct msghdr msg;
435 msg_in.Convert(&msg);
436 union {
437 char buffer[CMSG_SPACE(SZ * sizeof(int))];
438 struct cmsghdr this_aligns_buffer;
439 } u;
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700440 msg.msg_control = u.buffer;
Greg Hartman3c95aac2017-06-14 18:24:26 -0700441 msg.msg_controllen = sizeof(u.buffer);
442
443 cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700444 cmsg->cmsg_len = CMSG_LEN(SZ * sizeof(int));
Greg Hartman3c95aac2017-06-14 18:24:26 -0700445 cmsg->cmsg_level = SOL_SOCKET;
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700446 cmsg->cmsg_type = SCM_RIGHTS;
Greg Hartman3c95aac2017-06-14 18:24:26 -0700447 int* fd_array = reinterpret_cast<int*>(CMSG_DATA(cmsg));
Greg Hartman7d5e0bf2017-12-19 23:48:34 -0800448 for (size_t i = 0; i < SZ; ++i) {
Greg Hartman3c95aac2017-06-14 18:24:26 -0700449 fd_array[i] = fds[i]->fd_;
450 }
451 return SendMsg(&msg, flags);
452 }
453
Ryan Haining732b4602018-02-16 16:44:47 -0800454 int Shutdown(int how) {
455 errno = 0;
456 int rval = shutdown(fd_, how);
457 errno_ = errno;
458 return rval;
459 }
460
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700461 ssize_t SendTo(const void* buf, size_t len, int flags,
462 const struct sockaddr* dest_addr, socklen_t addrlen) {
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700463 errno = 0;
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700464 ssize_t rval =
465 TEMP_FAILURE_RETRY(sendto(fd_, buf, len, flags, dest_addr, addrlen));
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700466 errno_ = errno;
467 return rval;
468 }
469
470 void Set(fd_set* dest, int* max_index) const;
471
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700472 int SetSockOpt(int level, int optname, const void* optval, socklen_t optlen) {
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700473 errno = 0;
474 int rval = setsockopt(fd_, level, optname, optval, optlen);
475 errno_ = errno;
476 return rval;
477 }
478
479 const char* StrError() const {
480 errno = 0;
481 FileInstance* s = const_cast<FileInstance*>(this);
482 char* out = strerror_r(errno_, s->strerror_buf_, sizeof(strerror_buf_));
483
484 // From man page:
485 // strerror_r() returns a pointer to a string containing the error message.
486 // This may be either a pointer to a string that the function stores in
487 // buf, or a pointer to some (immutable) static string (in which case buf
488 // is unused).
489 if (out != s->strerror_buf_) {
Greg Hartman40b88f52017-06-22 15:34:11 -0700490 strncpy(s->strerror_buf_, out, sizeof(strerror_buf_));
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700491 }
492 return strerror_buf_;
493 }
494
Tomasz Wiszkowskiaf38c7c2017-08-14 12:33:11 -0700495 int TimerGet(struct itimerspec* curr_value) {
496 errno = 0;
497 int rval = timerfd_gettime(fd_, curr_value);
498 errno_ = errno;
499 return rval;
500 }
501
502 int TimerSet(int flags, const struct itimerspec* new_value,
Greg Hartmand0f20d42017-12-19 23:47:26 -0800503 struct itimerspec* old_value) {
Tomasz Wiszkowskiaf38c7c2017-08-14 12:33:11 -0700504 errno = 0;
505 int rval = timerfd_settime(fd_, flags, new_value, old_value);
506 errno_ = errno;
507 return rval;
508 }
509
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700510 ssize_t Truncate(off_t length) {
511 errno = 0;
512 ssize_t rval = TEMP_FAILURE_RETRY(ftruncate(fd_, length));
513 errno_ = errno;
514 return rval;
515 }
516
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700517 ssize_t Write(const void* buf, size_t count) {
518 errno = 0;
519 ssize_t rval = TEMP_FAILURE_RETRY(write(fd_, buf, count));
520 errno_ = errno;
521 return rval;
522 }
523
524 ssize_t WriteV(struct iovec* iov, int iovcount) {
525 errno = 0;
526 ssize_t rval = TEMP_FAILURE_RETRY(writev(fd_, iov, iovcount));
527 errno_ = errno;
528 return rval;
529 }
530
531 private:
532 FileInstance(int fd, int in_errno) : fd_(fd), errno_(in_errno) {
Jorge E. Moreira6ffa0cb2018-10-24 17:19:39 -0700533 // Ensure every file descriptor managed by a FileInstance has the CLOEXEC
534 // flag
535 TEMP_FAILURE_RETRY(fcntl(fd, F_SETFD, FD_CLOEXEC));
Cody Schuffelen4ede79d2019-11-13 13:24:12 -0800536 std::stringstream identity;
537 identity << "fd=" << fd << " @" << this;
538 identity_ = identity.str();
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700539 }
540
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700541 FileInstance* Accept(struct sockaddr* addr, socklen_t* addrlen) const {
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700542 int fd = TEMP_FAILURE_RETRY(accept(fd_, addr, addrlen));
543 if (fd == -1) {
544 return new FileInstance(fd, errno);
545 } else {
546 return new FileInstance(fd, 0);
547 }
548 }
549
550 int fd_;
551 int errno_;
Cody Schuffelen4ede79d2019-11-13 13:24:12 -0800552 std::string identity_;
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700553 char strerror_buf_[160];
554};
555
556/* Methods that need both a fully defined SharedFD and a fully defined
557 FileInstance. */
558
Ryan Haining412a6922018-12-19 14:43:09 -0800559inline SharedFD::SharedFD() : value_(FileInstance::ClosedInstance()) {}
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700560
Greg Hartman153b1062017-11-11 12:09:21 -0800561} // namespace cvd
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700562
563#endif // CUTTLEFISH_COMMON_COMMON_LIBS_FS_SHARED_FD_H_