blob: f5dd4518bdd2f5040cc92dbce7cf54109c927e63 [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>
36
37#include <errno.h>
38#include <fcntl.h>
39#include <string.h>
40#include <unistd.h>
41
42#include "common/libs/auto_resources/auto_resources.h"
43
44/**
45 * Classes to to enable safe access to files.
46 * POSIX kernels have an unfortunate habit of recycling file descriptors.
47 * That can cause problems like http://b/26121457 in code that doesn't manage
48 * file lifetimes properly. These classes implement an alternate interface
49 * that has some advantages:
50 *
51 * o References to files are tightly controlled
52 * o Files are auto-closed if they go out of scope
53 * o Files are life-time aware. It is impossible to close the instance twice.
54 * o File descriptors are always initialized. By default the descriptor is
55 * set to a closed instance.
56 *
57 * These classes are designed to mimic to POSIX interface as closely as
58 * possible. Specifically, they don't attempt to track the type of file
59 * descriptors and expose only the valid operations. This is by design, since
60 * it makes it easier to convert existing code to SharedFDs and avoids the
61 * possibility that new POSIX functionality will lead to large refactorings.
62 */
Greg Hartman153b1062017-11-11 12:09:21 -080063namespace cvd {
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -070064
65class FileInstance;
66
67/**
Greg Hartman3c95aac2017-06-14 18:24:26 -070068 * Describes the fields in msghdr that are honored by the *MsgAndFDs
69 * calls.
70 */
71struct InbandMessageHeader {
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -070072 void* msg_name;
73 socklen_t msg_namelen;
Greg Hartman3c95aac2017-06-14 18:24:26 -070074 struct iovec* msg_iov;
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -070075 size_t msg_iovlen;
76 int msg_flags;
Greg Hartman3c95aac2017-06-14 18:24:26 -070077
78 void Convert(struct msghdr* dest) const {
79 dest->msg_name = msg_name;
80 dest->msg_namelen = msg_namelen;
81 dest->msg_iov = msg_iov;
82 dest->msg_iovlen = msg_iovlen;
83 dest->msg_flags = msg_flags;
84 }
85};
86
87/**
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -070088 * Counted reference to a FileInstance.
89 *
90 * This is also the place where most new FileInstances are created. The creation
91 * mehtods correspond to the underlying POSIX calls.
92 *
93 * SharedFDs can be compared and stored in STL containers. The semantics are
94 * slightly different from POSIX file descriptors:
95 *
96 * o The value of the SharedFD is the identity of its underlying FileInstance.
97 *
98 * o Each newly created SharedFD has a unique, closed FileInstance:
99 * SharedFD a, b;
100 * assert (a != b);
101 * a = b;
102 * asssert(a == b);
103 *
104 * o The identity of the FileInstance is not affected by closing the file:
105 * SharedFD a, b;
106 * set<SharedFD> s;
107 * s.insert(a);
108 * assert(s.count(a) == 1);
109 * assert(s.count(b) == 0);
110 * a->Close();
111 * assert(s.count(a) == 1);
112 * assert(s.count(b) == 0);
113 *
114 * o FileInstances are never visibly recycled.
115 *
116 * o If all of the SharedFDs referring to a FileInstance go out of scope the
117 * file is closed and the FileInstance is recycled.
118 *
119 * Creation methods must ensure that no references to the new file descriptor
120 * escape. The underlying FileInstance should have the only reference to the
121 * file descriptor. Any method that needs to know the fd must be in either
122 * SharedFD or FileInstance.
123 *
124 * SharedFDs always have an underlying FileInstance, so all of the method
125 * calls are safe in accordance with the null object pattern.
126 *
127 * Errors on system calls that create new FileInstances, such as Open, are
128 * reported with a new, closed FileInstance with the errno set.
129 */
130class SharedFD {
131 public:
132 inline SharedFD();
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700133 SharedFD(const std::shared_ptr<FileInstance>& in) : value_(in) {}
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700134 // Reference the listener as a FileInstance to make this FD type agnostic.
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700135 static SharedFD Accept(const FileInstance& listener, struct sockaddr* addr,
136 socklen_t* addrlen);
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700137 static SharedFD Accept(const FileInstance& listener);
Greg Hartman3c95aac2017-06-14 18:24:26 -0700138 static SharedFD Dup(int unmanaged_fd);
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700139 static SharedFD GetControlSocket(const char* name);
140 // Returns false on failure, true on success.
141 static SharedFD Open(const char* pathname, int flags, mode_t mode = 0);
142 static bool Pipe(SharedFD* fd0, SharedFD* fd1);
Tomasz Wiszkowskid88403b2017-07-06 14:42:14 -0700143 static SharedFD Event(int initval = 0, int flags = 0);
Tomasz Wiszkowski16fb1742017-09-15 14:31:53 -0700144 static SharedFD Epoll(int flags = 0);
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700145 static bool SocketPair(int domain, int type, int protocol, SharedFD* fd0,
146 SharedFD* fd1);
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700147 static SharedFD Socket(int domain, int socket_type, int protocol);
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700148 static SharedFD SocketLocalClient(const char* name, bool is_abstract,
149 int in_type);
Ryan Hainingd5c1bde2018-01-29 13:34:22 -0800150 static SharedFD SocketLocalClient(int port, int type);
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700151 static SharedFD SocketLocalServer(const char* name, bool is_abstract,
152 int in_type, mode_t mode);
Jorge E. Moreira854bcbc2017-09-26 16:05:10 -0700153 static SharedFD SocketLocalServer(int port, int type);
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700154 static SharedFD SocketSeqPacketServer(const char* name, mode_t mode);
155 static SharedFD SocketSeqPacketClient(const char* name);
Tomasz Wiszkowskiaf38c7c2017-08-14 12:33:11 -0700156 static SharedFD TimerFD(int clock, int flags);
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700157
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700158 bool operator==(const SharedFD& rhs) const { return value_ == rhs.value_; }
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700159
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700160 bool operator!=(const SharedFD& rhs) const { return value_ != rhs.value_; }
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700161
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700162 bool operator<(const SharedFD& rhs) const { return value_ < rhs.value_; }
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700163
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700164 bool operator<=(const SharedFD& rhs) const { return value_ <= rhs.value_; }
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700165
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700166 bool operator>(const SharedFD& rhs) const { return value_ > rhs.value_; }
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700167
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700168 bool operator>=(const SharedFD& rhs) const { return value_ >= rhs.value_; }
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700169
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700170 std::shared_ptr<FileInstance> operator->() const { return value_; }
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700171
Greg Hartman153b1062017-11-11 12:09:21 -0800172 const cvd::FileInstance& operator*() const { return *value_; }
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700173
Greg Hartman153b1062017-11-11 12:09:21 -0800174 cvd::FileInstance& operator*() { return *value_; }
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700175
176 private:
177 std::shared_ptr<FileInstance> value_;
178};
179
180/**
181 * Tracks the lifetime of a file descriptor and provides methods to allow
182 * callers to use the file without knowledge of the underlying descriptor
183 * number.
184 *
185 * FileInstances have two states: Open and Closed. They may start in either
186 * state. However, once a FileIntance enters the Closed state it cannot be
187 * reopened.
188 *
189 * Construction of FileInstances is limited to select classes to avoid
190 * escaping file descriptors. At this point SharedFD is the only class
191 * that has access. We may eventually have ScopedFD and WeakFD.
192 */
193class FileInstance {
194 // Give SharedFD access to the aliasing constructor.
195 friend class SharedFD;
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700196
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700197 public:
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700198 virtual ~FileInstance() { Close(); }
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700199
200 // This can't be a singleton because our shared_ptr's aren't thread safe.
201 static std::shared_ptr<FileInstance> ClosedInstance() {
202 return std::shared_ptr<FileInstance>(new FileInstance(-1, EBADF));
203 }
204
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700205 int Bind(const struct sockaddr* addr, socklen_t addrlen) {
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700206 errno = 0;
207 int rval = bind(fd_, addr, addrlen);
208 errno_ = errno;
209 return rval;
210 }
211
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700212 int Connect(const struct sockaddr* addr, socklen_t addrlen) {
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700213 errno = 0;
214 int rval = connect(fd_, addr, addrlen);
215 errno_ = errno;
216 return rval;
217 }
218
219 void Close();
220
221 // Returns true if the entire input was copied.
222 // Otherwise an error will be set either on this file or the input.
223 // The non-const reference is needed to avoid binding this to a particular
224 // reference type.
225 bool CopyFrom(FileInstance& in);
Jorge E. Moreiracfbb4102018-07-02 18:53:24 -0700226 bool CopyFrom(FileInstance& in, size_t length);
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700227
228 int UNMANAGED_Dup() {
229 errno = 0;
230 int rval = TEMP_FAILURE_RETRY(dup(fd_));
231 errno_ = errno;
232 return rval;
233 }
234
Greg Hartman153b1062017-11-11 12:09:21 -0800235 int EpollCtl(int op, cvd::SharedFD new_fd, struct epoll_event* event) {
Tomasz Wiszkowski16fb1742017-09-15 14:31:53 -0700236 errno = 0;
Greg Hartmand0f20d42017-12-19 23:47:26 -0800237 int rval = TEMP_FAILURE_RETRY(epoll_ctl(fd_, op, new_fd->fd_, event));
Tomasz Wiszkowski16fb1742017-09-15 14:31:53 -0700238 errno_ = errno;
239 return rval;
240 }
241
242 int EpollWait(struct epoll_event* events, int maxevents, int timeout) {
243 errno = 0;
Greg Hartmand0f20d42017-12-19 23:47:26 -0800244 int rval = TEMP_FAILURE_RETRY(epoll_wait(fd_, events, maxevents, timeout));
Tomasz Wiszkowski16fb1742017-09-15 14:31:53 -0700245 errno_ = errno;
246 return rval;
247 }
248
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700249 int Fchown(uid_t owner, gid_t group) {
250 errno = 0;
251 int rval = TEMP_FAILURE_RETRY(fchown(fd_, owner, group));
252 errno_ = errno;
253 return rval;
254 }
255
256 int Fcntl(int command, int value) {
257 errno = 0;
258 int rval = TEMP_FAILURE_RETRY(fcntl(fd_, command, value));
259 errno_ = errno;
260 return rval;
261 }
262
263 int Fstat(struct stat* buf) {
264 errno = 0;
265 int rval = TEMP_FAILURE_RETRY(fstat(fd_, buf));
266 errno_ = errno;
267 return rval;
268 }
269
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700270 int GetErrno() const { return errno_; }
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700271
272 int GetSockOpt(int level, int optname, void* optval, socklen_t* optlen) {
273 errno = 0;
274 int rval = getsockopt(fd_, level, optname, optval, optlen);
275 if (rval == -1) {
276 errno_ = errno;
277 }
278 return rval;
279 }
280
281 void Identify(const char* identity);
282
Greg Hartman40b88f52017-06-22 15:34:11 -0700283 int Ioctl(int request, void* val = nullptr) {
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700284 errno = 0;
Greg Hartman40b88f52017-06-22 15:34:11 -0700285 int rval = TEMP_FAILURE_RETRY(ioctl(fd_, request, val));
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700286 errno_ = errno;
287 return rval;
288 }
289
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700290 bool IsOpen() const { return fd_ != -1; }
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700291
292 // in probably isn't modified, but the API spec doesn't have const.
293 bool IsSet(fd_set* in) const;
294
295 int Listen(int backlog) {
296 errno = 0;
297 int rval = listen(fd_, backlog);
298 errno_ = errno;
299 return rval;
300 }
301
302 static void Log(const char* message);
303
304 off_t LSeek(off_t offset, int whence) {
305 errno = 0;
306 off_t rval = TEMP_FAILURE_RETRY(lseek(fd_, offset, whence));
307 errno_ = errno;
308 return rval;
309 }
310
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700311 void* Mmap(void* addr, size_t length, int prot, int flags, off_t offset) {
Greg Hartman40b88f52017-06-22 15:34:11 -0700312 errno = 0;
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700313 void* rval = mmap(addr, length, prot, flags, fd_, offset);
Greg Hartman40b88f52017-06-22 15:34:11 -0700314 errno_ = errno;
315 return rval;
316 }
317
318 ssize_t Pread(void* buf, size_t count, off_t offset) {
319 errno = 0;
320 ssize_t rval = TEMP_FAILURE_RETRY(pread(fd_, buf, count, offset));
321 errno_ = errno;
322 return rval;
323 }
324
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700325 ssize_t Recv(void* buf, size_t len, int flags) {
326 errno = 0;
327 ssize_t rval = TEMP_FAILURE_RETRY(recv(fd_, buf, len, flags));
328 errno_ = errno;
329 return rval;
330 }
331
332 ssize_t RecvFrom(void* buf, size_t len, int flags, struct sockaddr* src_addr,
333 socklen_t* addr_len) {
334 errno = 0;
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700335 ssize_t rval =
336 TEMP_FAILURE_RETRY(recvfrom(fd_, buf, len, flags, src_addr, addr_len));
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700337 errno_ = errno;
338 return rval;
339 }
340
341 ssize_t RecvMsg(struct msghdr* msg, int flags) {
342 errno = 0;
343 ssize_t rval = TEMP_FAILURE_RETRY(recvmsg(fd_, msg, flags));
344 errno_ = errno;
345 return rval;
346 }
347
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700348 template <size_t SZ>
349 ssize_t RecvMsgAndFDs(const struct InbandMessageHeader& msg_in, int flags,
350 SharedFD (*new_fds)[SZ]) {
Greg Hartman3c95aac2017-06-14 18:24:26 -0700351 // We need to make some modifications to land the fds. Make it clear
352 // that there are no updates to the msg being passed in during this call.
353 struct msghdr msg;
354 msg_in.Convert(&msg);
355 union {
356 char buffer[CMSG_SPACE(SZ * sizeof(int))];
357 struct cmsghdr this_aligns_buffer;
358 } u;
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700359 msg.msg_control = u.buffer;
Greg Hartman3c95aac2017-06-14 18:24:26 -0700360 msg.msg_controllen = sizeof(u.buffer);
361
362 cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700363 cmsg->cmsg_len = CMSG_LEN(SZ * sizeof(int));
Greg Hartman3c95aac2017-06-14 18:24:26 -0700364 cmsg->cmsg_level = SOL_SOCKET;
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700365 cmsg->cmsg_type = SCM_RIGHTS;
Greg Hartman3c95aac2017-06-14 18:24:26 -0700366 int* fd_array = reinterpret_cast<int*>(CMSG_DATA(cmsg));
Greg Hartmanee76f042017-12-04 18:33:51 -0800367 for (size_t i = 0; i < SZ; ++i) {
Greg Hartman3c95aac2017-06-14 18:24:26 -0700368 fd_array[i] = -1;
369 }
370 ssize_t rval = RecvMsg(&msg, flags);
Greg Hartmanee76f042017-12-04 18:33:51 -0800371 for (size_t i = 0; i < SZ; ++i) {
Greg Hartman3c95aac2017-06-14 18:24:26 -0700372 (*new_fds)[i] =
373 std::shared_ptr<FileInstance>(new FileInstance(fd_array[i], errno));
374 }
375 return rval;
376 }
377
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700378 ssize_t Read(void* buf, size_t count) {
379 errno = 0;
380 ssize_t rval = TEMP_FAILURE_RETRY(read(fd_, buf, count));
381 errno_ = errno;
382 return rval;
383 }
384
385 ssize_t Send(const void* buf, size_t len, int flags) {
386 errno = 0;
387 ssize_t rval = TEMP_FAILURE_RETRY(send(fd_, buf, len, flags));
388 errno_ = errno;
389 return rval;
390 }
391
392 ssize_t SendMsg(const struct msghdr* msg, int flags) {
393 errno = 0;
394 ssize_t rval = TEMP_FAILURE_RETRY(sendmsg(fd_, msg, flags));
395 errno_ = errno;
396 return rval;
397 }
398
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700399 template <size_t SZ>
400 ssize_t SendMsgAndFDs(const struct InbandMessageHeader& msg_in, int flags,
401 const SharedFD (&fds)[SZ]) {
Greg Hartman3c95aac2017-06-14 18:24:26 -0700402 struct msghdr msg;
403 msg_in.Convert(&msg);
404 union {
405 char buffer[CMSG_SPACE(SZ * sizeof(int))];
406 struct cmsghdr this_aligns_buffer;
407 } u;
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700408 msg.msg_control = u.buffer;
Greg Hartman3c95aac2017-06-14 18:24:26 -0700409 msg.msg_controllen = sizeof(u.buffer);
410
411 cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700412 cmsg->cmsg_len = CMSG_LEN(SZ * sizeof(int));
Greg Hartman3c95aac2017-06-14 18:24:26 -0700413 cmsg->cmsg_level = SOL_SOCKET;
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700414 cmsg->cmsg_type = SCM_RIGHTS;
Greg Hartman3c95aac2017-06-14 18:24:26 -0700415 int* fd_array = reinterpret_cast<int*>(CMSG_DATA(cmsg));
Greg Hartman7d5e0bf2017-12-19 23:48:34 -0800416 for (size_t i = 0; i < SZ; ++i) {
Greg Hartman3c95aac2017-06-14 18:24:26 -0700417 fd_array[i] = fds[i]->fd_;
418 }
419 return SendMsg(&msg, flags);
420 }
421
Ryan Haining732b4602018-02-16 16:44:47 -0800422 int Shutdown(int how) {
423 errno = 0;
424 int rval = shutdown(fd_, how);
425 errno_ = errno;
426 return rval;
427 }
428
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700429 ssize_t SendTo(const void* buf, size_t len, int flags,
430 const struct sockaddr* dest_addr, socklen_t addrlen) {
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700431 errno = 0;
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700432 ssize_t rval =
433 TEMP_FAILURE_RETRY(sendto(fd_, buf, len, flags, dest_addr, addrlen));
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700434 errno_ = errno;
435 return rval;
436 }
437
438 void Set(fd_set* dest, int* max_index) const;
439
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700440 int SetSockOpt(int level, int optname, const void* optval, socklen_t optlen) {
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700441 errno = 0;
442 int rval = setsockopt(fd_, level, optname, optval, optlen);
443 errno_ = errno;
444 return rval;
445 }
446
447 const char* StrError() const {
448 errno = 0;
449 FileInstance* s = const_cast<FileInstance*>(this);
450 char* out = strerror_r(errno_, s->strerror_buf_, sizeof(strerror_buf_));
451
452 // From man page:
453 // strerror_r() returns a pointer to a string containing the error message.
454 // This may be either a pointer to a string that the function stores in
455 // buf, or a pointer to some (immutable) static string (in which case buf
456 // is unused).
457 if (out != s->strerror_buf_) {
Greg Hartman40b88f52017-06-22 15:34:11 -0700458 strncpy(s->strerror_buf_, out, sizeof(strerror_buf_));
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700459 }
460 return strerror_buf_;
461 }
462
Tomasz Wiszkowskiaf38c7c2017-08-14 12:33:11 -0700463 int TimerGet(struct itimerspec* curr_value) {
464 errno = 0;
465 int rval = timerfd_gettime(fd_, curr_value);
466 errno_ = errno;
467 return rval;
468 }
469
470 int TimerSet(int flags, const struct itimerspec* new_value,
Greg Hartmand0f20d42017-12-19 23:47:26 -0800471 struct itimerspec* old_value) {
Tomasz Wiszkowskiaf38c7c2017-08-14 12:33:11 -0700472 errno = 0;
473 int rval = timerfd_settime(fd_, flags, new_value, old_value);
474 errno_ = errno;
475 return rval;
476 }
477
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700478 ssize_t Truncate(off_t length) {
479 errno = 0;
480 ssize_t rval = TEMP_FAILURE_RETRY(ftruncate(fd_, length));
481 errno_ = errno;
482 return rval;
483 }
484
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700485 ssize_t Write(const void* buf, size_t count) {
486 errno = 0;
487 ssize_t rval = TEMP_FAILURE_RETRY(write(fd_, buf, count));
488 errno_ = errno;
489 return rval;
490 }
491
492 ssize_t WriteV(struct iovec* iov, int iovcount) {
493 errno = 0;
494 ssize_t rval = TEMP_FAILURE_RETRY(writev(fd_, iov, iovcount));
495 errno_ = errno;
496 return rval;
497 }
498
499 private:
500 FileInstance(int fd, int in_errno) : fd_(fd), errno_(in_errno) {
501 identity_.PrintF("fd=%d @%p", fd, this);
502 }
503
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700504 FileInstance* Accept(struct sockaddr* addr, socklen_t* addrlen) const {
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700505 int fd = TEMP_FAILURE_RETRY(accept(fd_, addr, addrlen));
506 if (fd == -1) {
507 return new FileInstance(fd, errno);
508 } else {
509 return new FileInstance(fd, 0);
510 }
511 }
512
513 int fd_;
514 int errno_;
515 AutoFreeBuffer identity_;
516 char strerror_buf_[160];
517};
518
519/* Methods that need both a fully defined SharedFD and a fully defined
520 FileInstance. */
521
Tomasz Wiszkowski2c359222017-07-05 14:00:13 -0700522SharedFD::SharedFD() : value_(FileInstance::ClosedInstance()) {}
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700523
Greg Hartman153b1062017-11-11 12:09:21 -0800524} // namespace cvd
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700525
526#endif // CUTTLEFISH_COMMON_COMMON_LIBS_FS_SHARED_FD_H_