blob: 6db27ee9c2ed8647d1e548311890d5323acd242b [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
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -070028#include "common/libs/auto_resources/auto_resources.h"
Greg Hartman40b88f52017-06-22 15:34:11 -070029#include "common/libs/glog/logging.h"
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -070030#include "common/libs/fs/shared_select.h"
31
32// #define ENABLE_GCE_SHARED_FD_LOGGING 1
33
34namespace {
Greg Hartman153b1062017-11-11 12:09:21 -080035using cvd::SharedFDSet;
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -070036
37void MarkAll(const SharedFDSet& input, fd_set* dest, int* max_index) {
38 for (SharedFDSet::const_iterator it = input.begin(); it != input.end();
39 ++it) {
40 (*it)->Set(dest, max_index);
41 }
42}
43
Tomasz Wiszkowski09c17782017-09-15 09:54:49 -070044void CheckMarked(fd_set* in_out_mask, SharedFDSet* in_out_set) {
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -070045 if (!in_out_set) {
46 return;
47 }
48 SharedFDSet save;
49 save.swap(in_out_set);
50 for (SharedFDSet::iterator it = save.begin(); it != save.end(); ++it) {
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -070051 if ((*it)->IsSet(in_out_mask)) {
52 in_out_set->Set(*it);
53 }
54 }
55}
56} // namespace
57
Greg Hartman153b1062017-11-11 12:09:21 -080058namespace cvd {
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -070059
60bool FileInstance::CopyFrom(FileInstance& in) {
Cody Schuffelen4ede79d2019-11-13 13:24:12 -080061 std::vector<char> buffer(8192);
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -070062 while (true) {
63 ssize_t num_read = in.Read(buffer.data(), buffer.size());
64 if (!num_read) {
65 return true;
66 }
67 if (num_read == -1) {
68 return false;
69 }
70 if (num_read > 0) {
71 if (Write(buffer.data(), num_read) != num_read) {
72 // The caller will have to log an appropriate message.
73 return false;
74 }
75 }
76 }
77 return true;
78}
79
Jorge E. Moreiracfbb4102018-07-02 18:53:24 -070080bool FileInstance::CopyFrom(FileInstance& in, size_t length) {
Cody Schuffelen4ede79d2019-11-13 13:24:12 -080081 std::vector<char> buffer(8192);
Jorge E. Moreiracfbb4102018-07-02 18:53:24 -070082 while (length > 0) {
83 ssize_t num_read = in.Read(buffer.data(), std::min(buffer.size(), length));
84 length -= num_read;
85 if (num_read <= 0) {
86 return false;
87 }
88 if (Write(buffer.data(), num_read) != num_read) {
89 // The caller will have to log an appropriate message.
90 return false;
91 }
92 }
93 return true;
94}
95
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -070096void FileInstance::Close() {
Cody Schuffelen4ede79d2019-11-13 13:24:12 -080097 std::stringstream message;
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -070098 if (fd_ == -1) {
99 errno_ = EBADF;
100 } else if (close(fd_) == -1) {
101 errno_ = errno;
102 if (identity_.size()) {
Cody Schuffelen4ede79d2019-11-13 13:24:12 -0800103 message << __FUNCTION__ << ": " << identity_ << " failed (" << StrError() << ")";
104 std::string message_str = message.str();
105 Log(message_str.c_str());
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700106 }
107 } else {
108 if (identity_.size()) {
Cody Schuffelen4ede79d2019-11-13 13:24:12 -0800109 message << __FUNCTION__ << ": " << identity_ << "succeeded";
110 std::string message_str = message.str();
111 Log(message_str.c_str());
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700112 }
113 }
114 fd_ = -1;
115}
116
117void FileInstance::Identify(const char* identity) {
Cody Schuffelen4ede79d2019-11-13 13:24:12 -0800118 std::stringstream identity_stream;
119 identity_stream << "fd=" << fd_ << " @" << this << " is " << identity;
120 identity_ = identity_stream.str();
121 std::stringstream message;
122 message << __FUNCTION__ << ": " << identity_;
123 std::string message_str = message.str();
124 Log(message_str.c_str());
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700125}
126
127bool FileInstance::IsSet(fd_set* in) const {
128 if (IsOpen() && FD_ISSET(fd_, in)) {
129 return true;
130 }
131 return false;
132}
133
134#if ENABLE_GCE_SHARED_FD_LOGGING
135void FileInstance::Log(const char* message) {
Greg Hartman67fa8582017-07-31 21:40:02 -0700136 LOG(INFO) << message;
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700137}
138#else
Tomasz Wiszkowskid88403b2017-07-06 14:42:14 -0700139void FileInstance::Log(const char*) {}
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700140#endif
141
142void FileInstance::Set(fd_set* dest, int* max_index) const {
143 if (!IsOpen()) {
144 return;
145 }
146 if (fd_ >= *max_index) {
147 *max_index = fd_ + 1;
148 }
149 FD_SET(fd_, dest);
150}
151
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700152int Select(SharedFDSet* read_set, SharedFDSet* write_set,
153 SharedFDSet* error_set, struct timeval* timeout) {
154 int max_index = 0;
155 fd_set readfds;
156 FD_ZERO(&readfds);
157 if (read_set) {
158 MarkAll(*read_set, &readfds, &max_index);
159 }
160 fd_set writefds;
161 FD_ZERO(&writefds);
162 if (write_set) {
163 MarkAll(*write_set, &writefds, &max_index);
164 }
165 fd_set errorfds;
166 FD_ZERO(&errorfds);
Tomasz Wiszkowski09c17782017-09-15 09:54:49 -0700167 if (error_set) {
168 MarkAll(*error_set, &errorfds, &max_index);
169 }
170
Tomasz Wiszkowskid88403b2017-07-06 14:42:14 -0700171 int rval = TEMP_FAILURE_RETRY(
172 select(max_index, &readfds, &writefds, &errorfds, timeout));
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700173 FileInstance::Log("select\n");
Tomasz Wiszkowski09c17782017-09-15 09:54:49 -0700174 CheckMarked(&readfds, read_set);
175 CheckMarked(&writefds, write_set);
176 CheckMarked(&errorfds, error_set);
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700177 return rval;
178}
179
Tomasz Wiszkowskid88403b2017-07-06 14:42:14 -0700180static void MakeAddress(const char* name, bool abstract,
181 struct sockaddr_un* dest, socklen_t* len) {
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700182 memset(dest, 0, sizeof(*dest));
183 dest->sun_family = AF_UNIX;
184 // sun_path is NOT expected to be nul-terminated.
185 // See man 7 unix.
Ping-Hao Wu75cc1e02017-06-06 16:39:14 -0700186 size_t namelen;
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700187 if (abstract) {
Ping-Hao Wu75cc1e02017-06-06 16:39:14 -0700188 // ANDROID_SOCKET_NAMESPACE_ABSTRACT
189 namelen = strlen(name);
190 CHECK_LE(namelen, sizeof(dest->sun_path) - 1)
191 << "MakeAddress failed. Name=" << name << " is longer than allowed.";
192 dest->sun_path[0] = 0;
193 memcpy(dest->sun_path + 1, name, namelen);
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700194 } else {
Ping-Hao Wu75cc1e02017-06-06 16:39:14 -0700195 // ANDROID_SOCKET_NAMESPACE_RESERVED
196 // ANDROID_SOCKET_NAMESPACE_FILESYSTEM
197 // TODO(pinghao): Distinguish between them?
198 namelen = strlen(name);
199 CHECK_LE(namelen, sizeof(dest->sun_path))
200 << "MakeAddress failed. Name=" << name << " is longer than allowed.";
201 strncpy(dest->sun_path, name, strlen(name));
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700202 }
Ping-Hao Wu75cc1e02017-06-06 16:39:14 -0700203 *len = namelen + offsetof(struct sockaddr_un, sun_path) + 1;
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700204}
205
206SharedFD SharedFD::SocketSeqPacketServer(const char* name, mode_t mode) {
207 return SocketLocalServer(name, false, SOCK_SEQPACKET, mode);
208}
209
210SharedFD SharedFD::SocketSeqPacketClient(const char* name) {
211 return SocketLocalClient(name, false, SOCK_SEQPACKET);
212}
213
Tomasz Wiszkowskiaf38c7c2017-08-14 12:33:11 -0700214SharedFD SharedFD::TimerFD(int clock, int flags) {
215 int fd = timerfd_create(clock, flags);
216 if (fd == -1) {
217 return SharedFD(std::shared_ptr<FileInstance>(new FileInstance(fd, errno)));
218 } else {
219 return SharedFD(std::shared_ptr<FileInstance>(new FileInstance(fd, 0)));
220 }
221}
222
Tomasz Wiszkowskid88403b2017-07-06 14:42:14 -0700223SharedFD SharedFD::Accept(const FileInstance& listener, struct sockaddr* addr,
224 socklen_t* addrlen) {
225 return SharedFD(
226 std::shared_ptr<FileInstance>(listener.Accept(addr, addrlen)));
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -0700227}
228
229SharedFD SharedFD::Accept(const FileInstance& listener) {
230 return SharedFD::Accept(listener, NULL, NULL);
231}
232
Greg Hartman3c95aac2017-06-14 18:24:26 -0700233SharedFD SharedFD::Dup(int unmanaged_fd) {
234 int fd = dup(unmanaged_fd);
235 return SharedFD(std::shared_ptr<FileInstance>(new FileInstance(fd, errno)));
236}
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