blob: cd5580457c7b854c0db7eb92bf653b71bab36573 [file] [log] [blame]
// Copyright 2016 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 "webserv_common/binder_constants.h"
#include "libwebserv/binder_request_handler.h"
#include "libwebserv/binder_server.h"
#include "libwebserv/protocol_handler.h"
#include "libwebserv/request_handler_callback.h"
#include <map>
#include <set>
#include <string>
#include <vector>
using android::sp;
using android::IBinder;
using android::binder::Status;
using android::webservd::IProtocolHandler;
using android::webservd::IRequestHandler;
using std::map;
using std::pair;
using std::set;
using std::string;
using std::unique_ptr;
using std::vector;
namespace libwebserv {
class RequestHandlerRegistration {
public:
RequestHandlerRegistration(const string& url,
const string& method,
unique_ptr<RequestHandlerInterface> handler)
: url_(url),
method_(method),
handler_(std::move(handler)),
binder_handler_(new BinderRequestHandler(handler_.get())) {}
~RequestHandlerRegistration() { DropRemotes(); }
void AddRemote(sp<IProtocolHandler> handler) {
string guid;
if (!handler->AddRequestHandler(url_,
method_,
binder_handler_,
&guid).isOk()) {
LOG(WARNING) << "Remote protocol handler failed to "
<< "register new request handler.";
}
protos_.emplace_back(handler, guid);
}
void DropRemotes() {
for (auto& proto : protos_) {
if (!proto.first->RemoveRequestHandler(proto.second).isOk()) {
LOG(WARNING) << "Could not remove request handler from remote.";
}
}
}
private:
string url_;
string method_;
unique_ptr<RequestHandlerInterface> handler_;
sp<IRequestHandler> binder_handler_;
vector<pair<sp<IProtocolHandler>, string>> protos_;
DISALLOW_COPY_AND_ASSIGN(RequestHandlerRegistration);
};
// This is libwebserv's binder based process local protocol
// handler. It wraps around a group of remote protocol handlers
// that share a common name. It exists independently of the
// lifetime of the remote protocol handlers and is created on
// either of:
// 1) The local process requests a protocol handler by name
// 2) We connect to the remote webservd process and it has a protocol
// handler with the given name.
class BinderProtocolHandler : public ProtocolHandler {
public:
explicit BinderProtocolHandler(const string& name)
: name_(name) {}
virtual ~BinderProtocolHandler() {
ResetRemoteProtocolHandlers();
}
bool AddRemote(sp<IProtocolHandler> handler) {
string name;
int32_t port;
string protocol;
if (!handler->GetName(&name).isOk()) {
LOG(INFO) << "Could not get name of remote protocol handler.";
return false;
}
CHECK(name == name_);
if (!handler->GetPort(&port).isOk()) {
LOG(INFO) << "Could not get port for remote protocol handler.";
return false;
}
if (!handler->GetProtocol(&protocol).isOk()) {
LOG(INFO) << "Could not get protocol for remote protocol handler.";
return false;
}
ports_.insert(uint16_t(port));
protocols_.insert(protocol);
remote_handlers_.push_back(handler);
for (auto& request_handler : request_handler_ids_) {
request_handler.second->AddRemote(handler);
}
return true;
}
int AddHandler(const string& url,
const string& method,
unique_ptr<RequestHandlerInterface> handler) override {
unique_ptr<RequestHandlerRegistration> registration(
new RequestHandlerRegistration(url, method, std::move(handler)));
for (sp<IProtocolHandler> remote : remote_handlers_) {
registration->AddRemote(remote);
}
int id = last_handler_id_++;
request_handler_ids_.emplace(id, std::move(registration));
return id;
}
int AddHandlerCallback(
const string& url,
const string& method,
const base::Callback<RequestHandlerInterface::HandlerSignature>&
handler_callback) override {
std::unique_ptr<RequestHandlerInterface> handler{
new RequestHandlerCallback{handler_callback}};
return AddHandler(url, method, std::move(handler));
}
bool RemoveHandler(int handler_id) override {
return request_handler_ids_.erase(handler_id) > 0;
}
void ResetRemoteProtocolHandlers() {
for (auto& it : request_handler_ids_) {
it.second->DropRemotes();
}
remote_handlers_.clear();
}
bool IsConnected() const override { return !remote_handlers_.empty(); }
string GetName() const override { return name_; }
set<uint16_t> GetPorts() const override { return ports_; }
set<string> GetProtocols() const override { return protocols_; }
brillo::Blob GetCertificateFingerprint() const override {
brillo::Blob result;
for (auto& handler : remote_handlers_) {
Status status = handler->GetCertificateFingerprint(&result);
if (!status.isOk()) {
LOG(WARNING) << "Could not get certificate fingerprint "
<< "from protocol handler: " << status;
} else if (!result.empty()) {
break;
}
}
return result;
}
private:
int last_handler_id_ = 0;
set<uint16_t> ports_;
set<string> protocols_;
string name_;
vector<sp<IProtocolHandler>> remote_handlers_;
// Map of local handler IDs to objects containing the various bits of IPC
// state we need to maintain those handlers on the remote end.
map<int,unique_ptr<RequestHandlerRegistration>> request_handler_ids_;
DISALLOW_COPY_AND_ASSIGN(BinderProtocolHandler);
};
BinderServer::BinderServer(brillo::MessageLoop* message_loop,
const base::Closure& on_server_online,
const base::Closure& on_server_offline,
android::BinderWrapper* binder_wrapper)
: message_loop_{message_loop},
on_server_online_{on_server_online},
on_server_offline_{on_server_offline},
binder_wrapper_{binder_wrapper} {
message_loop_->PostTask(FROM_HERE,
base::Bind(&BinderServer::TryConnecting,
weak_ptr_factory_.GetWeakPtr()));
}
void BinderServer::TryConnecting() {
ClearLocalState();
sp<IBinder> binder = binder_wrapper_->GetService(
webservd::kWebserverBinderServiceName);
if (!binder.get()) {
LOG(INFO) << "Webservd has not registered with service manager.";
} else if (!BuildLocalState(binder)) {
ClearLocalState();
} else {
if (!on_server_online_.is_null()) {
message_loop_->PostTask(FROM_HERE, on_server_online_);
}
// Got a binder, built up appropriate local state, our job is done.
return;
}
message_loop_->PostDelayedTask(FROM_HERE,
base::Bind(&BinderServer::TryConnecting,
weak_ptr_factory_.GetWeakPtr()),
base::TimeDelta::FromSeconds(1));
}
void BinderServer::ClearLocalState() {
for (auto& local_handler: local_protocol_handlers_) {
local_handler.second->ResetRemoteProtocolHandlers();
if (!on_protocol_handler_disconnected_.is_null()) {
message_loop_->PostTask(
FROM_HERE, base::Bind(on_protocol_handler_disconnected_,
base::Unretained(local_handler.second.get())));
}
}
if (remote_server_.get() && !on_server_offline_.is_null()) {
message_loop_->PostTask(FROM_HERE, on_server_offline_);
}
remote_server_.clear();
}
bool BinderServer::BuildLocalState(sp<IBinder> server) {
remote_server_ = android::interface_cast<RemoteServer>(server);
vector<sp<IBinder>> remote_raw_binders;
if (!remote_server_->GetProtocolHandlers("", &remote_raw_binders).isOk()) {
// Possibly the server died, this is not necessarily an error.
LOG(INFO) << "Webservd failed to tell us about protocol handlers.";
return false;
}
// Tell the local wrappers about the remote handlers that exist now.
for (auto& raw_binder: remote_raw_binders) {
sp<RemoteProtocolHandler> remote_handler =
android::interface_cast<RemoteProtocolHandler>(raw_binder);
string name;
if (!remote_handler->GetName(&name).isOk()) {
LOG(INFO) << "Remote handler could not report its name.";
return false;
}
auto it = local_protocol_handlers_.find(name);
if (it == local_protocol_handlers_.end()) {
unique_ptr<BinderProtocolHandler> local_handler(
new BinderProtocolHandler(name));
it = local_protocol_handlers_.emplace(name,
std::move(local_handler)).first;
}
it->second->AddRemote(remote_handler);
if (!on_protocol_handler_connected_.is_null()) {
message_loop_->PostTask(FROM_HERE,
base::Bind(on_protocol_handler_connected_,
base::Unretained(it->second.get())));
}
}
return true;
}
ProtocolHandler* BinderServer::GetDefaultHttpHandler() {
return GetProtocolHandler(ProtocolHandler::kHttp);
}
ProtocolHandler* BinderServer::GetDefaultHttpsHandler() {
return GetProtocolHandler(ProtocolHandler::kHttps);
}
ProtocolHandler* BinderServer::GetProtocolHandler(const string& name) {
auto it = local_protocol_handlers_.find(name);
if (it == local_protocol_handlers_.end()) {
unique_ptr<BinderProtocolHandler> local_handler(
new BinderProtocolHandler(name));
it = local_protocol_handlers_.emplace(name,
std::move(local_handler)).first;
}
return it->second.get();
}
bool BinderServer::IsConnected() const {
return remote_server_.get() != nullptr;
}
void BinderServer::OnProtocolHandlerConnected(
const base::Callback<void(ProtocolHandler*)>& callback) {
on_protocol_handler_connected_ = callback;
for (auto& handler : local_protocol_handlers_) {
if (handler.second->IsConnected()) {
message_loop_->PostTask(
FROM_HERE,
base::Bind(callback, base::Unretained(handler.second.get())));
}
}
}
void BinderServer::OnProtocolHandlerDisconnected(
const base::Callback<void(ProtocolHandler*)>& callback) {
on_protocol_handler_disconnected_ = callback;
for (auto& handler : local_protocol_handlers_) {
if (!handler.second->IsConnected()) {
message_loop_->PostTask(
FROM_HERE,
base::Bind(callback, base::Unretained(handler.second.get())));
}
}
}
base::TimeDelta BinderServer::GetDefaultRequestTimeout() const {
int32_t timeout_seconds;
if (!remote_server_->GetDefaultRequestTimeout(&timeout_seconds).isOk()) {
LOG(ERROR) << "Could not get request timeout from remote server.";
// Precedent from the DBus server says this is the error return value.
return base::TimeDelta::Max();
}
return base::TimeDelta::FromSeconds(timeout_seconds);
}
} // namespace libwebserv