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