| // 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 { |
| // 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()))); |
| } |
| } |
| |
| 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 |