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