blob: 4ac8636c86d53c2f60a87ce87111a3f9cddca7d2 [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_server.h"
#include "libwebserv/protocol_handler.h"
#include "libwebserv/request_handler_callback.h"
#include "android/webservd/BnRequestHandler.h"
#include <map>
#include <set>
#include <string>
#include <vector>
using android::sp;
using android::IBinder;
using android::binder::Status;
using android::webservd::IHttpRequest;
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 BinderRequestHandler : public android::webservd::BnRequestHandler {
public:
explicit BinderRequestHandler(unique_ptr<RequestHandlerInterface> handler)
: handler_(std::move(handler)) {}
Status ProcessRequest(const sp<IHttpRequest>& request) override {
(void)request;
return Status::ok();
}
private:
unique_ptr<RequestHandlerInterface> handler_;
DISALLOW_COPY_AND_ASSIGN(BinderRequestHandler);
};
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);
return true;
}
int AddHandler(const string& url,
const string& method,
unique_ptr<RequestHandlerInterface> handler) override {
sp<IRequestHandler> binder_handler(
new BinderRequestHandler(std::move(handler)));
set<pair<sp<IProtocolHandler>, string>> guids;
// Add this local request handler to each remote protocol handler
// associated with this local protocol handler.
for (sp<IProtocolHandler> handler : remote_handlers_) {
string guid;
if (!handler->AddRequestHandler(url,
method,
binder_handler,
&guid).isOk()) {
LOG(WARNING) << "Remote protocol handler failed to "
<< "register new request handler.";
} else {
guids.emplace(handler, guid);
}
}
int id = last_handler_id_++;
handler_ids_.emplace(id, guids);
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 {
auto it = handler_ids_.find(handler_id);
if (it == handler_ids_.end()) {
return false;
}
for (const pair<sp<IProtocolHandler>,string>& remote : it->second) {
if (!remote.first->RemoveRequestHandler(remote.second).isOk()) {
LOG(WARNING) << "Could not remove request handler from remote.";
}
}
return true;
}
void ResetRemoteProtocolHandlers() {
for (auto it : handler_ids_) {
for (auto remote : it.second) {
if (!remote.first->RemoveRequestHandler(remote.second).isOk()) {
LOG(INFO) << "Could not remove request handler from remote.";
}
}
}
handler_ids_.clear();
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 handler ID numbers as returned by AddHandler to pairs of
// IProtocolHandler pointers and string handler GUIDs as returned by the
// daemon.
map<int,set<pair<sp<IProtocolHandler>,string>>> 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();
android::sp<android::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 {
// 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();
}
remote_server_.clear();
}
bool BinderServer::BuildLocalState(android::sp<android::IBinder> server) {
remote_server_ = android::interface_cast<RemoteServer>(server);
vector<sp<IBinder>> remote_raw_binders;
if (!remote_server_->GetProtocolHandlers(nullptr,
&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));
local_protocol_handlers_[name] = std::move(local_handler);
it = local_protocol_handlers_.find(name);
}
it->second->AddRemote(remote_handler);
}
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()) {
return nullptr;
}
return it->second.get();
}
bool BinderServer::IsConnected() const {
return remote_server_.get() != nullptr;
}
void BinderServer::OnProtocolHandlerConnected(
const base::Callback<void(ProtocolHandler*)>& /*callback*/) {
}
void BinderServer::OnProtocolHandlerDisconnected(
const base::Callback<void(ProtocolHandler*)>& /*callback*/) {
}
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