1 #include <uds/client_channel_factory.h> 2 3 #include <errno.h> 4 #include <log/log.h> 5 #include <sys/socket.h> 6 #include <sys/un.h> 7 #include <unistd.h> 8 9 #include <chrono> 10 #include <thread> 11 12 #include <uds/channel_manager.h> 13 #include <uds/client_channel.h> 14 #include <uds/ipc_helper.h> 15 16 using std::chrono::duration_cast; 17 using std::chrono::steady_clock; 18 19 namespace android { 20 namespace pdx { 21 namespace uds { 22 23 std::string ClientChannelFactory::GetRootEndpointPath() { 24 return "/dev/socket/pdx"; 25 } 26 27 std::string ClientChannelFactory::GetEndpointPath( 28 const std::string& endpoint_path) { 29 std::string path; 30 if (!endpoint_path.empty()) { 31 if (endpoint_path.front() == '/') 32 path = endpoint_path; 33 else 34 path = GetRootEndpointPath() + '/' + endpoint_path; 35 } 36 return path; 37 } 38 39 ClientChannelFactory::ClientChannelFactory(const std::string& endpoint_path) 40 : endpoint_path_{GetEndpointPath(endpoint_path)} {} 41 42 ClientChannelFactory::ClientChannelFactory(LocalHandle socket) 43 : socket_{std::move(socket)} {} 44 45 std::unique_ptr<pdx::ClientChannelFactory> ClientChannelFactory::Create( 46 const std::string& endpoint_path) { 47 return std::unique_ptr<pdx::ClientChannelFactory>{ 48 new ClientChannelFactory{endpoint_path}}; 49 } 50 51 std::unique_ptr<pdx::ClientChannelFactory> ClientChannelFactory::Create( 52 LocalHandle socket) { 53 return std::unique_ptr<pdx::ClientChannelFactory>{ 54 new ClientChannelFactory{std::move(socket)}}; 55 } 56 57 Status<std::unique_ptr<pdx::ClientChannel>> ClientChannelFactory::Connect( 58 int64_t timeout_ms) const { 59 Status<void> status; 60 61 bool connected = socket_.IsValid(); 62 if (!connected) { 63 socket_.Reset(socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)); 64 LOG_ALWAYS_FATAL_IF( 65 endpoint_path_.empty(), 66 "ClientChannelFactory::Connect: unspecified socket path"); 67 } 68 69 if (!socket_) { 70 ALOGE("ClientChannelFactory::Connect: socket error: %s", strerror(errno)); 71 return ErrorStatus(errno); 72 } 73 74 bool use_timeout = (timeout_ms >= 0); 75 auto now = steady_clock::now(); 76 auto time_end = now + std::chrono::milliseconds{timeout_ms}; 77 78 int max_eaccess = 5; // Max number of times to retry when EACCES returned. 79 while (!connected) { 80 int64_t timeout = -1; 81 if (use_timeout) { 82 auto remaining = time_end - now; 83 timeout = duration_cast<std::chrono::milliseconds>(remaining).count(); 84 if (timeout < 0) 85 return ErrorStatus(ETIMEDOUT); 86 } 87 sockaddr_un remote; 88 remote.sun_family = AF_UNIX; 89 strncpy(remote.sun_path, endpoint_path_.c_str(), sizeof(remote.sun_path)); 90 remote.sun_path[sizeof(remote.sun_path) - 1] = '\0'; 91 ALOGD("ClientChannelFactory: Waiting for endpoint at %s", remote.sun_path); 92 status = WaitForEndpoint(endpoint_path_, timeout); 93 if (!status) 94 return ErrorStatus(status.error()); 95 96 ALOGD("ClientChannelFactory: Connecting to %s", remote.sun_path); 97 int ret = RETRY_EINTR(connect( 98 socket_.Get(), reinterpret_cast<sockaddr*>(&remote), sizeof(remote))); 99 if (ret == -1) { 100 ALOGD("ClientChannelFactory: Connect error %d: %s", errno, 101 strerror(errno)); 102 // if |max_eaccess| below reaches zero when errno is EACCES, the control 103 // flows into the next "else if" statement and a permanent error is 104 // returned from this function. 105 if (errno == ECONNREFUSED || (errno == EACCES && max_eaccess-- > 0)) { 106 // Connection refused/Permission denied can be the result of connecting 107 // too early (the service socket is created but its access rights are 108 // not set or not being listened to yet). 109 ALOGD("ClientChannelFactory: %s, waiting...", strerror(errno)); 110 using namespace std::literals::chrono_literals; 111 std::this_thread::sleep_for(100ms); 112 } else if (errno != ENOENT && errno != ENOTDIR) { 113 // ENOENT/ENOTDIR might mean that the socket file/directory containing 114 // it has been just deleted. Try to wait for its creation and do not 115 // return an error immediately. 116 ALOGE( 117 "ClientChannelFactory::Connect: Failed to initialize connection " 118 "when connecting: %s", 119 strerror(errno)); 120 return ErrorStatus(errno); 121 } 122 } else { 123 connected = true; 124 ALOGD("ClientChannelFactory: Connected successfully to %s...", 125 remote.sun_path); 126 ChannelConnectionInfo<LocalHandle> connection_info; 127 status = ReceiveData(socket_.Borrow(), &connection_info); 128 if (!status) 129 return status.error_status(); 130 socket_ = std::move(connection_info.channel_fd); 131 if (!socket_) { 132 ALOGE("ClientChannelFactory::Connect: Failed to obtain channel socket"); 133 return ErrorStatus(EIO); 134 } 135 } 136 if (use_timeout) 137 now = steady_clock::now(); 138 } // while (!connected) 139 140 RequestHeader<BorrowedHandle> request; 141 InitRequest(&request, opcodes::CHANNEL_OPEN, 0, 0, false); 142 status = SendData(socket_.Borrow(), request); 143 if (!status) 144 return status.error_status(); 145 ResponseHeader<LocalHandle> response; 146 status = ReceiveData(socket_.Borrow(), &response); 147 if (!status) 148 return status.error_status(); 149 int ref = response.ret_code; 150 if (ref < 0 || static_cast<size_t>(ref) > response.file_descriptors.size()) 151 return ErrorStatus(EIO); 152 153 LocalHandle event_fd = std::move(response.file_descriptors[ref]); 154 return ClientChannel::Create(ChannelManager::Get().CreateHandle( 155 std::move(socket_), std::move(event_fd))); 156 } 157 158 } // namespace uds 159 } // namespace pdx 160 } // namespace android 161