| // 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(const 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 (const 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.toString8(); | |
| } 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(const 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 |