blob: 2f878bf04ab3c2c681ad2e1d80866fbef0180242 [file] [log] [blame]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "client/pairing/pairing_client.h"
#include <atomic>
#include <iomanip>
#include <mutex>
#include <sstream>
#include <thread>
#include <vector>
#include <android-base/logging.h>
#include <android-base/parsenetaddress.h>
#include <android-base/stringprintf.h>
#include <android-base/thread_annotations.h>
#include <android-base/unique_fd.h>
#include <cutils/sockets.h>
#include "sysdeps.h"
namespace adbwifi {
namespace pairing {
using android::base::unique_fd;
namespace {
struct ConnectionDeleter {
void operator()(PairingConnectionCtx* p) { pairing_connection_destroy(p); }
}; // ConnectionDeleter
using ConnectionPtr = std::unique_ptr<PairingConnectionCtx, ConnectionDeleter>;
class PairingClientImpl : public PairingClient {
public:
virtual ~PairingClientImpl();
explicit PairingClientImpl(const Data& pswd, const PeerInfo& peer_info, const Data& cert,
const Data& priv_key);
// Starts the pairing client. This call is non-blocking. Upon pairing
// completion, |cb| will be called with the PeerInfo on success,
// or an empty value on failure.
//
// Returns true if PairingClient was successfully started. Otherwise,
// return false.
virtual bool Start(std::string_view ip_addr, pairing_client_result_cb cb,
void* opaque) override;
static void OnPairingResult(const PeerInfo* peer_info, int fd, void* opaque);
private:
// Setup and start the PairingConnection
bool StartConnection();
enum class State {
Ready,
Running,
Stopped,
};
State state_ = State::Ready;
Data pswd_;
PeerInfo peer_info_;
Data cert_;
Data priv_key_;
std::string host_;
int port_;
ConnectionPtr connection_;
pairing_client_result_cb cb_;
void* opaque_ = nullptr;
}; // PairingClientImpl
PairingClientImpl::PairingClientImpl(const Data& pswd, const PeerInfo& peer_info, const Data& cert,
const Data& priv_key)
: pswd_(pswd), peer_info_(peer_info), cert_(cert), priv_key_(priv_key) {
CHECK(!pswd_.empty() && !cert_.empty() && !priv_key_.empty());
state_ = State::Ready;
}
PairingClientImpl::~PairingClientImpl() {
// Make sure to kill the PairingConnection before terminating the fdevent
// looper.
if (connection_ != nullptr) {
connection_.reset();
}
}
bool PairingClientImpl::Start(std::string_view ip_addr, pairing_client_result_cb cb, void* opaque) {
CHECK(!ip_addr.empty());
cb_ = cb;
opaque_ = opaque;
if (state_ != State::Ready) {
LOG(ERROR) << "PairingClient already running or finished";
return false;
}
// Try to parse the host address
std::string err;
CHECK(android::base::ParseNetAddress(std::string(ip_addr), &host_, &port_, nullptr, &err));
CHECK(port_ > 0 && port_ <= 65535);
if (!StartConnection()) {
LOG(ERROR) << "Unable to start PairingClient connection";
state_ = State::Stopped;
return false;
}
state_ = State::Running;
return true;
}
bool PairingClientImpl::StartConnection() {
std::string err;
const int timeout = 10; // seconds
unique_fd fd(network_connect(host_, port_, SOCK_STREAM, timeout, &err));
if (fd.get() == -1) {
LOG(ERROR) << "Failed to start pairing connection client [" << err << "]";
return false;
}
int off = 1;
adb_setsockopt(fd.get(), IPPROTO_TCP, TCP_NODELAY, &off, sizeof(off));
connection_ = ConnectionPtr(
pairing_connection_client_new(pswd_.data(), pswd_.size(), &peer_info_, cert_.data(),
cert_.size(), priv_key_.data(), priv_key_.size()));
CHECK(connection_);
if (!pairing_connection_start(connection_.get(), fd.release(), OnPairingResult, this)) {
LOG(ERROR) << "PairingClient failed to start the PairingConnection";
state_ = State::Stopped;
return false;
}
return true;
}
// static
void PairingClientImpl::OnPairingResult(const PeerInfo* peer_info, int /* fd */, void* opaque) {
auto* p = reinterpret_cast<PairingClientImpl*>(opaque);
p->cb_(peer_info, p->opaque_);
}
} // namespace
// static
std::unique_ptr<PairingClient> PairingClient::Create(const Data& pswd, const PeerInfo& peer_info,
const Data& cert, const Data& priv_key) {
CHECK(!pswd.empty());
CHECK(!cert.empty());
CHECK(!priv_key.empty());
return std::unique_ptr<PairingClient>(new PairingClientImpl(pswd, peer_info, cert, priv_key));
}
} // namespace pairing
} // namespace adbwifi