• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <sys/types.h>
19 #include <sys/stat.h>
20 #include <cstddef>
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <netinet/in.h>
24 #include <unistd.h>
25 #include <algorithm>
26 
27 #include "common/libs/auto_resources/auto_resources.h"
28 #include "common/libs/glog/logging.h"
29 #include "common/libs/fs/shared_select.h"
30 
31 // #define ENABLE_GCE_SHARED_FD_LOGGING 1
32 
33 namespace {
34 using cvd::SharedFDSet;
35 
MarkAll(const SharedFDSet & input,fd_set * dest,int * max_index)36 void MarkAll(const SharedFDSet& input, fd_set* dest, int* max_index) {
37   for (SharedFDSet::const_iterator it = input.begin(); it != input.end();
38        ++it) {
39     (*it)->Set(dest, max_index);
40   }
41 }
42 
CheckMarked(fd_set * in_out_mask,SharedFDSet * in_out_set)43 void CheckMarked(fd_set* in_out_mask, SharedFDSet* in_out_set) {
44   if (!in_out_set) {
45     return;
46   }
47   SharedFDSet save;
48   save.swap(in_out_set);
49   for (SharedFDSet::iterator it = save.begin(); it != save.end(); ++it) {
50     if ((*it)->IsSet(in_out_mask)) {
51       in_out_set->Set(*it);
52     }
53   }
54 }
55 }  // namespace
56 
57 namespace cvd {
58 
CopyFrom(FileInstance & in)59 bool FileInstance::CopyFrom(FileInstance& in) {
60   AutoFreeBuffer buffer;
61   buffer.Resize(8192);
62   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 
CopyFrom(FileInstance & in,size_t length)80 bool FileInstance::CopyFrom(FileInstance& in, size_t length) {
81   AutoFreeBuffer buffer;
82   buffer.Resize(8192);
83   while (length > 0) {
84     ssize_t num_read = in.Read(buffer.data(), std::min(buffer.size(), length));
85     length -= num_read;
86     if (num_read <= 0) {
87       return false;
88     }
89     if (Write(buffer.data(), num_read) != num_read) {
90       // The caller will have to log an appropriate message.
91       return false;
92     }
93   }
94   return true;
95 }
96 
Close()97 void FileInstance::Close() {
98   AutoFreeBuffer message;
99   if (fd_ == -1) {
100     errno_ = EBADF;
101   } else if (close(fd_) == -1) {
102     errno_ = errno;
103     if (identity_.size()) {
104       message.PrintF("%s: %s failed (%s)", __FUNCTION__, identity_.data(),
105                      StrError());
106       Log(message.data());
107     }
108   } else {
109     if (identity_.size()) {
110       message.PrintF("%s: %s succeeded", __FUNCTION__, identity_.data());
111       Log(message.data());
112     }
113   }
114   fd_ = -1;
115 }
116 
Identify(const char * identity)117 void FileInstance::Identify(const char* identity) {
118   identity_.PrintF("fd=%d @%p is %s", fd_, this, identity);
119   AutoFreeBuffer message;
120   message.PrintF("%s: %s", __FUNCTION__, identity_.data());
121   Log(message.data());
122 }
123 
IsSet(fd_set * in) const124 bool FileInstance::IsSet(fd_set* in) const {
125   if (IsOpen() && FD_ISSET(fd_, in)) {
126     return true;
127   }
128   return false;
129 }
130 
131 #if ENABLE_GCE_SHARED_FD_LOGGING
Log(const char * message)132 void FileInstance::Log(const char* message) {
133   LOG(INFO) << message;
134 }
135 #else
Log(const char *)136 void FileInstance::Log(const char*) {}
137 #endif
138 
Set(fd_set * dest,int * max_index) const139 void FileInstance::Set(fd_set* dest, int* max_index) const {
140   if (!IsOpen()) {
141     return;
142   }
143   if (fd_ >= *max_index) {
144     *max_index = fd_ + 1;
145   }
146   FD_SET(fd_, dest);
147 }
148 
Select(SharedFDSet * read_set,SharedFDSet * write_set,SharedFDSet * error_set,struct timeval * timeout)149 int Select(SharedFDSet* read_set, SharedFDSet* write_set,
150            SharedFDSet* error_set, struct timeval* timeout) {
151   int max_index = 0;
152   fd_set readfds;
153   FD_ZERO(&readfds);
154   if (read_set) {
155     MarkAll(*read_set, &readfds, &max_index);
156   }
157   fd_set writefds;
158   FD_ZERO(&writefds);
159   if (write_set) {
160     MarkAll(*write_set, &writefds, &max_index);
161   }
162   fd_set errorfds;
163   FD_ZERO(&errorfds);
164   if (error_set) {
165     MarkAll(*error_set, &errorfds, &max_index);
166   }
167 
168   int rval = TEMP_FAILURE_RETRY(
169       select(max_index, &readfds, &writefds, &errorfds, timeout));
170   FileInstance::Log("select\n");
171   CheckMarked(&readfds, read_set);
172   CheckMarked(&writefds, write_set);
173   CheckMarked(&errorfds, error_set);
174   return rval;
175 }
176 
MakeAddress(const char * name,bool abstract,struct sockaddr_un * dest,socklen_t * len)177 static void MakeAddress(const char* name, bool abstract,
178                         struct sockaddr_un* dest, socklen_t* len) {
179   memset(dest, 0, sizeof(*dest));
180   dest->sun_family = AF_UNIX;
181   // sun_path is NOT expected to be nul-terminated.
182   // See man 7 unix.
183   size_t namelen;
184   if (abstract) {
185     // ANDROID_SOCKET_NAMESPACE_ABSTRACT
186     namelen = strlen(name);
187     CHECK_LE(namelen, sizeof(dest->sun_path) - 1)
188         << "MakeAddress failed. Name=" << name << " is longer than allowed.";
189     dest->sun_path[0] = 0;
190     memcpy(dest->sun_path + 1, name, namelen);
191   } else {
192     // ANDROID_SOCKET_NAMESPACE_RESERVED
193     // ANDROID_SOCKET_NAMESPACE_FILESYSTEM
194     // TODO(pinghao): Distinguish between them?
195     namelen = strlen(name);
196     CHECK_LE(namelen, sizeof(dest->sun_path))
197         << "MakeAddress failed. Name=" << name << " is longer than allowed.";
198     strncpy(dest->sun_path, name, strlen(name));
199   }
200   *len = namelen + offsetof(struct sockaddr_un, sun_path) + 1;
201 }
202 
SocketSeqPacketServer(const char * name,mode_t mode)203 SharedFD SharedFD::SocketSeqPacketServer(const char* name, mode_t mode) {
204   return SocketLocalServer(name, false, SOCK_SEQPACKET, mode);
205 }
206 
SocketSeqPacketClient(const char * name)207 SharedFD SharedFD::SocketSeqPacketClient(const char* name) {
208   return SocketLocalClient(name, false, SOCK_SEQPACKET);
209 }
210 
TimerFD(int clock,int flags)211 SharedFD SharedFD::TimerFD(int clock, int flags) {
212   int fd = timerfd_create(clock, flags);
213   if (fd == -1) {
214     return SharedFD(std::shared_ptr<FileInstance>(new FileInstance(fd, errno)));
215   } else {
216     return SharedFD(std::shared_ptr<FileInstance>(new FileInstance(fd, 0)));
217   }
218 }
219 
Accept(const FileInstance & listener,struct sockaddr * addr,socklen_t * addrlen)220 SharedFD SharedFD::Accept(const FileInstance& listener, struct sockaddr* addr,
221                           socklen_t* addrlen) {
222   return SharedFD(
223       std::shared_ptr<FileInstance>(listener.Accept(addr, addrlen)));
224 }
225 
Accept(const FileInstance & listener)226 SharedFD SharedFD::Accept(const FileInstance& listener) {
227   return SharedFD::Accept(listener, NULL, NULL);
228 }
229 
Dup(int unmanaged_fd)230 SharedFD SharedFD::Dup(int unmanaged_fd) {
231   int fd = dup(unmanaged_fd);
232   return SharedFD(std::shared_ptr<FileInstance>(new FileInstance(fd, errno)));
233 }
234 
Pipe(SharedFD * fd0,SharedFD * fd1)235 bool SharedFD::Pipe(SharedFD* fd0, SharedFD* fd1) {
236   int fds[2];
237   int rval = pipe(fds);
238   if (rval != -1) {
239     (*fd0) = std::shared_ptr<FileInstance>(new FileInstance(fds[0], errno));
240     (*fd1) = std::shared_ptr<FileInstance>(new FileInstance(fds[1], errno));
241     return true;
242   }
243   return false;
244 }
245 
Event(int initval,int flags)246 SharedFD SharedFD::Event(int initval, int flags) {
247   return std::shared_ptr<FileInstance>(
248       new FileInstance(eventfd(initval, flags), errno));
249 }
250 
Epoll(int flags)251 SharedFD SharedFD::Epoll(int flags) {
252   return std::shared_ptr<FileInstance>(
253       new FileInstance(epoll_create1(flags), errno));
254 }
255 
SocketPair(int domain,int type,int protocol,SharedFD * fd0,SharedFD * fd1)256 bool SharedFD::SocketPair(int domain, int type, int protocol,
257                           SharedFD* fd0, SharedFD* fd1) {
258   int fds[2];
259   int rval = socketpair(domain, type, protocol, fds);
260   if (rval != -1) {
261     (*fd0) = std::shared_ptr<FileInstance>(new FileInstance(fds[0], errno));
262     (*fd1) = std::shared_ptr<FileInstance>(new FileInstance(fds[1], errno));
263     return true;
264   }
265   return false;
266 }
267 
Open(const char * path,int flags,mode_t mode)268 SharedFD SharedFD::Open(const char* path, int flags, mode_t mode) {
269   int fd = TEMP_FAILURE_RETRY(open(path, flags, mode));
270   if (fd == -1) {
271     return SharedFD(std::shared_ptr<FileInstance>(new FileInstance(fd, errno)));
272   } else {
273     return SharedFD(std::shared_ptr<FileInstance>(new FileInstance(fd, 0)));
274   }
275 }
276 
Creat(const char * path,mode_t mode)277 SharedFD SharedFD::Creat(const char* path, mode_t mode) {
278   return SharedFD::Open(path, O_CREAT|O_WRONLY|O_TRUNC, mode);
279 }
280 
Socket(int domain,int socket_type,int protocol)281 SharedFD SharedFD::Socket(int domain, int socket_type, int protocol) {
282   int fd = TEMP_FAILURE_RETRY(socket(domain, socket_type, protocol));
283   if (fd == -1) {
284     return SharedFD(std::shared_ptr<FileInstance>(new FileInstance(fd, errno)));
285   } else {
286     return SharedFD(std::shared_ptr<FileInstance>(new FileInstance(fd, 0)));
287   }
288 }
289 
ErrorFD(int error)290 SharedFD SharedFD::ErrorFD(int error) {
291   return SharedFD(std::shared_ptr<FileInstance>(new FileInstance(-1, error)));
292 }
293 
SocketLocalClient(const char * name,bool abstract,int in_type)294 SharedFD SharedFD::SocketLocalClient(const char* name, bool abstract,
295                                      int in_type) {
296   struct sockaddr_un addr;
297   socklen_t addrlen;
298   MakeAddress(name, abstract, &addr, &addrlen);
299   SharedFD rval = SharedFD::Socket(PF_UNIX, in_type, 0);
300   if (!rval->IsOpen()) {
301     return rval;
302   }
303   if (rval->Connect(reinterpret_cast<sockaddr*>(&addr), addrlen) == -1) {
304     return SharedFD::ErrorFD(rval->GetErrno());
305   }
306   return rval;
307 }
308 
SocketLocalClient(int port,int type)309 SharedFD SharedFD::SocketLocalClient(int port, int type) {
310   sockaddr_in addr{};
311   addr.sin_family = AF_INET;
312   addr.sin_port = htons(port);
313   addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
314   SharedFD rval = SharedFD::Socket(AF_INET, type, 0);
315   if (!rval->IsOpen()) {
316     return rval;
317   }
318   if (rval->Connect(reinterpret_cast<const sockaddr*>(&addr),
319                     sizeof addr) < 0) {
320     return SharedFD::ErrorFD(rval->GetErrno());
321   }
322   return rval;
323 }
324 
SocketLocalServer(int port,int type)325 SharedFD SharedFD::SocketLocalServer(int port, int type) {
326   struct sockaddr_in addr;
327   memset(&addr, 0, sizeof(addr));
328   addr.sin_family = AF_INET;
329   addr.sin_port = htons(port);
330   addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
331   SharedFD rval = SharedFD::Socket(AF_INET, type, 0);
332   if(!rval->IsOpen()) {
333     return rval;
334   }
335   int n = 1;
336   if (rval->SetSockOpt(SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)) == -1) {
337     LOG(ERROR) << "SetSockOpt failed " << rval->StrError();
338     return SharedFD::ErrorFD(rval->GetErrno());
339   }
340   if(rval->Bind(reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) < 0) {
341     LOG(ERROR) << "Bind failed " << rval->StrError();
342     return SharedFD::ErrorFD(rval->GetErrno());
343   }
344   if (type == SOCK_STREAM) {
345     if (rval->Listen(4) < 0) {
346       LOG(ERROR) << "Listen failed " << rval->StrError();
347       return SharedFD::ErrorFD(rval->GetErrno());
348     }
349   }
350   return rval;
351 }
352 
SocketLocalServer(const char * name,bool abstract,int in_type,mode_t mode)353 SharedFD SharedFD::SocketLocalServer(const char* name, bool abstract,
354                                      int in_type, mode_t mode) {
355   // DO NOT UNLINK addr.sun_path. It does NOT have to be null-terminated.
356   // See man 7 unix for more details.
357   if (!abstract) (void)unlink(name);
358 
359   struct sockaddr_un addr;
360   socklen_t addrlen;
361   MakeAddress(name, abstract, &addr, &addrlen);
362   SharedFD rval = SharedFD::Socket(PF_UNIX, in_type, 0);
363   if (!rval->IsOpen()) {
364     return rval;
365   }
366 
367   int n = 1;
368   if (rval->SetSockOpt(SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)) == -1) {
369     LOG(ERROR) << "SetSockOpt failed " << rval->StrError();
370     return SharedFD::ErrorFD(rval->GetErrno());
371   }
372   if (rval->Bind(reinterpret_cast<sockaddr*>(&addr), addrlen) == -1) {
373     LOG(ERROR) << "Bind failed; name=" << name << ": " << rval->StrError();
374     return SharedFD::ErrorFD(rval->GetErrno());
375   }
376 
377   /* Only the bottom bits are really the socket type; there are flags too. */
378   constexpr int SOCK_TYPE_MASK = 0xf;
379 
380   // Connection oriented sockets: start listening.
381   if ((in_type & SOCK_TYPE_MASK) == SOCK_STREAM) {
382     // Follows the default from socket_local_server
383     if (rval->Listen(1) == -1) {
384       LOG(ERROR) << "Listen failed: " << rval->StrError();
385       return SharedFD::ErrorFD(rval->GetErrno());
386     }
387   }
388 
389   if (!abstract) {
390     if (TEMP_FAILURE_RETRY(chmod(name, mode)) == -1) {
391       LOG(ERROR) << "chmod failed: " << strerror(errno);
392       // However, continue since we do have a listening socket
393     }
394   }
395   return rval;
396 }
397 
VsockServer(unsigned int port,int type)398 SharedFD SharedFD::VsockServer(unsigned int port, int type) {
399   auto vsock = cvd::SharedFD::Socket(AF_VSOCK, type, 0);
400   if (!vsock->IsOpen()) {
401     return vsock;
402   }
403   sockaddr_vm addr{};
404   addr.svm_family = AF_VSOCK;
405   addr.svm_port = port;
406   addr.svm_cid = VMADDR_CID_ANY;
407   auto casted_addr = reinterpret_cast<sockaddr*>(&addr);
408   if (vsock->Bind(casted_addr, sizeof(addr)) == -1) {
409     LOG(ERROR) << "Bind failed (" << vsock->StrError() << ")";
410     return SharedFD::ErrorFD(vsock->GetErrno());
411   }
412   if (type == SOCK_STREAM) {
413     if (vsock->Listen(4) < 0) {
414       LOG(ERROR) << "Listen failed (" << vsock->StrError() << ")";
415       return SharedFD::ErrorFD(vsock->GetErrno());
416     }
417   }
418   return vsock;
419 }
420 
VsockClient(unsigned int cid,unsigned int port,int type)421 SharedFD SharedFD::VsockClient(unsigned int cid, unsigned int port, int type) {
422   auto vsock = cvd::SharedFD::Socket(AF_VSOCK, type, 0);
423   if (!vsock->IsOpen()) {
424     return vsock;
425   }
426   sockaddr_vm addr{};
427   addr.svm_family = AF_VSOCK;
428   addr.svm_port = port;
429   addr.svm_cid = cid;
430   auto casted_addr = reinterpret_cast<sockaddr*>(&addr);
431   if (vsock->Connect(casted_addr, sizeof(addr)) == -1) {
432     return SharedFD::ErrorFD(vsock->GetErrno());
433   }
434   return vsock;
435 }
436 
437 }  // namespace cvd
438