1 /*
2 * Copyright (C) 2020 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
17 #include "pairing_client.h"
18
19 #include <netdb.h>
20 #include <netinet/tcp.h>
21
22 #include <atomic>
23 #include <iomanip>
24 #include <mutex>
25 #include <sstream>
26 #include <thread>
27 #include <vector>
28
29 #include <android-base/logging.h>
30 #include <android-base/parsenetaddress.h>
31 #include <android-base/stringprintf.h>
32 #include <android-base/thread_annotations.h>
33 #include <android-base/unique_fd.h>
34 #include <cutils/sockets.h>
35
36 namespace adb {
37 namespace pairing {
38
39 using android::base::unique_fd;
40
ConnectionDeleter(PairingConnectionCtx * p)41 static void ConnectionDeleter(PairingConnectionCtx* p) {
42 pairing_connection_destroy(p);
43 }
44 using ConnectionPtr = std::unique_ptr<PairingConnectionCtx, decltype(&ConnectionDeleter)>;
45
46 namespace {
47
48 class PairingClientImpl : public PairingClient {
49 public:
50 explicit PairingClientImpl(const Data& pswd, const PeerInfo& peer_info, const Data& cert,
51 const Data& priv_key);
52
53 // Starts the pairing client. This call is non-blocking. Upon pairing
54 // completion, |cb| will be called with the PeerInfo on success,
55 // or an empty value on failure.
56 //
57 // Returns true if PairingClient was successfully started. Otherwise,
58 // return false.
59 virtual bool Start(std::string_view ip_addr, pairing_client_result_cb cb,
60 void* opaque) override;
61
62 private:
63 static ConnectionPtr CreatePairingConnection(const Data& pswd, const PeerInfo& peer_info,
64 const Data& cert, const Data& priv_key);
65
66 static void PairingResultCallback(const PeerInfo* peer_info, int fd, void* opaque);
67 // Setup and start the PairingConnection
68 bool StartConnection();
69
70 enum class State {
71 Ready,
72 Running,
73 Stopped,
74 };
75
76 State state_ = State::Ready;
77 Data pswd_;
78 PeerInfo peer_info_;
79 Data cert_;
80 Data priv_key_;
81 std::string host_;
82 int port_;
83
84 ConnectionPtr connection_;
85 pairing_client_result_cb cb_;
86 void* opaque_ = nullptr;
87 }; // PairingClientImpl
88
89 // static
CreatePairingConnection(const Data & pswd,const PeerInfo & peer_info,const Data & cert,const Data & priv_key)90 ConnectionPtr PairingClientImpl::CreatePairingConnection(const Data& pswd,
91 const PeerInfo& peer_info,
92 const Data& cert, const Data& priv_key) {
93 return ConnectionPtr(
94 pairing_connection_client_new(pswd.data(), pswd.size(), &peer_info, cert.data(),
95 cert.size(), priv_key.data(), priv_key.size()),
96 ConnectionDeleter);
97 }
98
PairingClientImpl(const Data & pswd,const PeerInfo & peer_info,const Data & cert,const Data & priv_key)99 PairingClientImpl::PairingClientImpl(const Data& pswd, const PeerInfo& peer_info, const Data& cert,
100 const Data& priv_key)
101 : pswd_(pswd),
102 peer_info_(peer_info),
103 cert_(cert),
104 priv_key_(priv_key),
105 connection_(nullptr, ConnectionDeleter) {
106 CHECK(!pswd_.empty() && !cert_.empty() && !priv_key_.empty());
107
108 state_ = State::Ready;
109 }
110
Start(std::string_view ip_addr,pairing_client_result_cb cb,void * opaque)111 bool PairingClientImpl::Start(std::string_view ip_addr, pairing_client_result_cb cb, void* opaque) {
112 CHECK(!ip_addr.empty());
113 cb_ = cb;
114 opaque_ = opaque;
115
116 if (state_ != State::Ready) {
117 LOG(ERROR) << "PairingClient already running or finished";
118 return false;
119 }
120
121 // Try to parse the host address
122 std::string err;
123 CHECK(android::base::ParseNetAddress(std::string(ip_addr), &host_, &port_, nullptr, &err));
124 CHECK(port_ > 0 && port_ <= 65535);
125
126 if (!StartConnection()) {
127 LOG(ERROR) << "Unable to start PairingClient connection";
128 state_ = State::Stopped;
129 return false;
130 }
131
132 state_ = State::Running;
133 return true;
134 }
135
network_connect(const std::string & host,int port,int type,int timeout,std::string * error)136 static int network_connect(const std::string& host, int port, int type, int timeout,
137 std::string* error) {
138 int getaddrinfo_error = 0;
139 int fd = socket_network_client_timeout(host.c_str(), port, type, timeout, &getaddrinfo_error);
140 if (fd != -1) {
141 return fd;
142 }
143 if (getaddrinfo_error != 0) {
144 *error = android::base::StringPrintf("failed to resolve host: '%s': %s", host.c_str(),
145 gai_strerror(getaddrinfo_error));
146 LOG(WARNING) << *error;
147 } else {
148 *error = android::base::StringPrintf("failed to connect to '%s:%d': %s", host.c_str(), port,
149 strerror(errno));
150 LOG(WARNING) << *error;
151 }
152 return -1;
153 }
154
155 // static
PairingResultCallback(const PeerInfo * peer_info,int,void * opaque)156 void PairingClientImpl::PairingResultCallback(const PeerInfo* peer_info, int /* fd */,
157 void* opaque) {
158 auto* p = reinterpret_cast<PairingClientImpl*>(opaque);
159 p->cb_(peer_info, p->opaque_);
160 }
161
StartConnection()162 bool PairingClientImpl::StartConnection() {
163 std::string err;
164 const int timeout = 10; // seconds
165 unique_fd fd(network_connect(host_, port_, SOCK_STREAM, timeout, &err));
166 if (fd.get() == -1) {
167 LOG(ERROR) << "Failed to start pairing connection client [" << err << "]";
168 return false;
169 }
170 int off = 1;
171 setsockopt(fd.get(), IPPROTO_TCP, TCP_NODELAY, &off, sizeof(off));
172
173 connection_ = CreatePairingConnection(pswd_, peer_info_, cert_, priv_key_);
174 if (connection_ == nullptr) {
175 LOG(ERROR) << "PairingClient unable to create a PairingConnection";
176 return false;
177 }
178
179 if (!pairing_connection_start(connection_.get(), fd.release(), PairingResultCallback, this)) {
180 LOG(ERROR) << "PairingClient failed to start the PairingConnection";
181 state_ = State::Stopped;
182 return false;
183 }
184
185 return true;
186 }
187
188 } // namespace
189
190 // static
Create(const Data & pswd,const PeerInfo & peer_info,const Data & cert,const Data & priv_key)191 std::unique_ptr<PairingClient> PairingClient::Create(const Data& pswd, const PeerInfo& peer_info,
192 const Data& cert, const Data& priv_key) {
193 CHECK(!pswd.empty());
194 CHECK(!cert.empty());
195 CHECK(!priv_key.empty());
196
197 return std::unique_ptr<PairingClient>(new PairingClientImpl(pswd, peer_info, cert, priv_key));
198 }
199
200 } // namespace pairing
201 } // namespace adb
202