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