Christopher Wiley | d6197ec | 2016-01-11 17:05:13 -0800 | [diff] [blame] | 1 | // Copyright 2016 The Android Open Source Project |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | // you may not use this file except in compliance with the License. |
| 5 | // You may obtain a copy of the License at |
| 6 | // |
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. |
| 14 | |
Casey Dahlin | 24d0e75 | 2016-02-05 15:48:01 -0800 | [diff] [blame] | 15 | #include "webserv_common/binder_constants.h" |
Christopher Wiley | d6197ec | 2016-01-11 17:05:13 -0800 | [diff] [blame] | 16 | |
Casey Dahlin | 242fa23 | 2016-02-17 17:01:55 -0800 | [diff] [blame] | 17 | #include "libwebserv/binder_request_handler.h" |
Casey Dahlin | 730b0d5 | 2016-02-16 18:22:46 -0800 | [diff] [blame] | 18 | #include "libwebserv/binder_server.h" |
| 19 | #include "libwebserv/protocol_handler.h" |
| 20 | #include "libwebserv/request_handler_callback.h" |
| 21 | |
Casey Dahlin | 730b0d5 | 2016-02-16 18:22:46 -0800 | [diff] [blame] | 22 | #include <map> |
| 23 | #include <set> |
Christopher Wiley | d6197ec | 2016-01-11 17:05:13 -0800 | [diff] [blame] | 24 | #include <string> |
| 25 | #include <vector> |
| 26 | |
Christopher Wiley | d6197ec | 2016-01-11 17:05:13 -0800 | [diff] [blame] | 27 | using android::sp; |
| 28 | using android::IBinder; |
Casey Dahlin | 2f69b81 | 2016-02-16 14:10:48 -0800 | [diff] [blame] | 29 | using android::binder::Status; |
Casey Dahlin | 730b0d5 | 2016-02-16 18:22:46 -0800 | [diff] [blame] | 30 | using android::webservd::IProtocolHandler; |
| 31 | using android::webservd::IRequestHandler; |
| 32 | using std::map; |
| 33 | using std::pair; |
| 34 | using std::set; |
Christopher Wiley | d6197ec | 2016-01-11 17:05:13 -0800 | [diff] [blame] | 35 | using std::string; |
Casey Dahlin | 730b0d5 | 2016-02-16 18:22:46 -0800 | [diff] [blame] | 36 | using std::unique_ptr; |
Christopher Wiley | d6197ec | 2016-01-11 17:05:13 -0800 | [diff] [blame] | 37 | using std::vector; |
| 38 | |
| 39 | namespace libwebserv { |
| 40 | |
Casey Dahlin | f42e559 | 2016-03-02 14:09:10 -0800 | [diff] [blame] | 41 | class RequestHandlerRegistration { |
| 42 | public: |
| 43 | RequestHandlerRegistration(const string& url, |
| 44 | const string& method, |
| 45 | unique_ptr<RequestHandlerInterface> handler) |
| 46 | : url_(url), |
| 47 | method_(method), |
| 48 | handler_(std::move(handler)), |
| 49 | binder_handler_(new BinderRequestHandler(handler_.get())) {} |
| 50 | |
| 51 | ~RequestHandlerRegistration() { DropRemotes(); } |
| 52 | |
| 53 | void AddRemote(sp<IProtocolHandler> handler) { |
| 54 | string guid; |
| 55 | |
| 56 | if (!handler->AddRequestHandler(url_, |
| 57 | method_, |
| 58 | binder_handler_, |
| 59 | &guid).isOk()) { |
| 60 | LOG(WARNING) << "Remote protocol handler failed to " |
| 61 | << "register new request handler."; |
| 62 | } |
| 63 | |
| 64 | protos_.emplace_back(handler, guid); |
| 65 | } |
| 66 | |
| 67 | void DropRemotes() { |
| 68 | for (auto& proto : protos_) { |
| 69 | if (!proto.first->RemoveRequestHandler(proto.second).isOk()) { |
| 70 | LOG(WARNING) << "Could not remove request handler from remote."; |
| 71 | } |
| 72 | } |
| 73 | } |
| 74 | |
| 75 | private: |
| 76 | string url_; |
| 77 | string method_; |
| 78 | unique_ptr<RequestHandlerInterface> handler_; |
| 79 | sp<IRequestHandler> binder_handler_; |
| 80 | vector<pair<sp<IProtocolHandler>, string>> protos_; |
| 81 | |
| 82 | DISALLOW_COPY_AND_ASSIGN(RequestHandlerRegistration); |
| 83 | }; |
| 84 | |
| 85 | // This is libwebserv's binder based process local protocol |
| 86 | // handler. It wraps around a group of remote protocol handlers |
| 87 | // that share a common name. It exists independently of the |
| 88 | // lifetime of the remote protocol handlers and is created on |
| 89 | // either of: |
| 90 | // 1) The local process requests a protocol handler by name |
| 91 | // 2) We connect to the remote webservd process and it has a protocol |
| 92 | // handler with the given name. |
Casey Dahlin | 730b0d5 | 2016-02-16 18:22:46 -0800 | [diff] [blame] | 93 | class BinderProtocolHandler : public ProtocolHandler { |
| 94 | public: |
| 95 | explicit BinderProtocolHandler(const string& name) |
| 96 | : name_(name) {} |
| 97 | |
| 98 | virtual ~BinderProtocolHandler() { |
| 99 | ResetRemoteProtocolHandlers(); |
| 100 | } |
| 101 | |
| 102 | bool AddRemote(sp<IProtocolHandler> handler) { |
| 103 | string name; |
| 104 | int32_t port; |
| 105 | string protocol; |
| 106 | |
| 107 | if (!handler->GetName(&name).isOk()) { |
| 108 | LOG(INFO) << "Could not get name of remote protocol handler."; |
| 109 | return false; |
| 110 | } |
| 111 | |
| 112 | CHECK(name == name_); |
| 113 | |
| 114 | if (!handler->GetPort(&port).isOk()) { |
| 115 | LOG(INFO) << "Could not get port for remote protocol handler."; |
| 116 | return false; |
| 117 | } |
| 118 | |
| 119 | if (!handler->GetProtocol(&protocol).isOk()) { |
| 120 | LOG(INFO) << "Could not get protocol for remote protocol handler."; |
| 121 | return false; |
| 122 | } |
| 123 | |
| 124 | ports_.insert(uint16_t(port)); |
| 125 | protocols_.insert(protocol); |
| 126 | remote_handlers_.push_back(handler); |
| 127 | |
Casey Dahlin | f42e559 | 2016-03-02 14:09:10 -0800 | [diff] [blame] | 128 | for (auto& request_handler : request_handler_ids_) { |
| 129 | request_handler.second->AddRemote(handler); |
| 130 | } |
| 131 | |
Casey Dahlin | 730b0d5 | 2016-02-16 18:22:46 -0800 | [diff] [blame] | 132 | return true; |
| 133 | } |
| 134 | |
| 135 | int AddHandler(const string& url, |
| 136 | const string& method, |
| 137 | unique_ptr<RequestHandlerInterface> handler) override { |
Casey Dahlin | f42e559 | 2016-03-02 14:09:10 -0800 | [diff] [blame] | 138 | unique_ptr<RequestHandlerRegistration> registration( |
| 139 | new RequestHandlerRegistration(url, method, std::move(handler))); |
Casey Dahlin | 730b0d5 | 2016-02-16 18:22:46 -0800 | [diff] [blame] | 140 | |
Casey Dahlin | f42e559 | 2016-03-02 14:09:10 -0800 | [diff] [blame] | 141 | for (sp<IProtocolHandler> remote : remote_handlers_) { |
| 142 | registration->AddRemote(remote); |
Casey Dahlin | 730b0d5 | 2016-02-16 18:22:46 -0800 | [diff] [blame] | 143 | } |
| 144 | |
| 145 | int id = last_handler_id_++; |
Casey Dahlin | f42e559 | 2016-03-02 14:09:10 -0800 | [diff] [blame] | 146 | |
| 147 | request_handler_ids_.emplace(id, std::move(registration)); |
| 148 | |
Casey Dahlin | 730b0d5 | 2016-02-16 18:22:46 -0800 | [diff] [blame] | 149 | return id; |
| 150 | } |
| 151 | |
| 152 | int AddHandlerCallback( |
| 153 | const string& url, |
| 154 | const string& method, |
| 155 | const base::Callback<RequestHandlerInterface::HandlerSignature>& |
| 156 | handler_callback) override { |
| 157 | std::unique_ptr<RequestHandlerInterface> handler{ |
| 158 | new RequestHandlerCallback{handler_callback}}; |
| 159 | return AddHandler(url, method, std::move(handler)); |
| 160 | } |
| 161 | |
| 162 | bool RemoveHandler(int handler_id) override { |
Casey Dahlin | f42e559 | 2016-03-02 14:09:10 -0800 | [diff] [blame] | 163 | return request_handler_ids_.erase(handler_id) > 0; |
Casey Dahlin | 730b0d5 | 2016-02-16 18:22:46 -0800 | [diff] [blame] | 164 | } |
| 165 | |
| 166 | void ResetRemoteProtocolHandlers() { |
Casey Dahlin | f42e559 | 2016-03-02 14:09:10 -0800 | [diff] [blame] | 167 | for (auto& it : request_handler_ids_) { |
| 168 | it.second->DropRemotes(); |
Casey Dahlin | 730b0d5 | 2016-02-16 18:22:46 -0800 | [diff] [blame] | 169 | } |
| 170 | |
Casey Dahlin | 730b0d5 | 2016-02-16 18:22:46 -0800 | [diff] [blame] | 171 | remote_handlers_.clear(); |
| 172 | } |
| 173 | |
| 174 | bool IsConnected() const override { return !remote_handlers_.empty(); } |
| 175 | string GetName() const override { return name_; } |
| 176 | set<uint16_t> GetPorts() const override { return ports_; } |
| 177 | set<string> GetProtocols() const override { return protocols_; } |
| 178 | |
| 179 | brillo::Blob GetCertificateFingerprint() const override { |
| 180 | brillo::Blob result; |
| 181 | |
| 182 | for (auto& handler : remote_handlers_) { |
| 183 | Status status = handler->GetCertificateFingerprint(&result); |
| 184 | if (!status.isOk()) { |
| 185 | LOG(WARNING) << "Could not get certificate fingerprint " |
Ralph Nathan | 9419e66 | 2016-04-13 13:42:07 -0700 | [diff] [blame] | 186 | << "from protocol handler: " << status.toString8(); |
Casey Dahlin | 730b0d5 | 2016-02-16 18:22:46 -0800 | [diff] [blame] | 187 | } else if (!result.empty()) { |
| 188 | break; |
| 189 | } |
| 190 | } |
| 191 | |
| 192 | return result; |
| 193 | } |
| 194 | |
| 195 | private: |
| 196 | int last_handler_id_ = 0; |
| 197 | set<uint16_t> ports_; |
| 198 | set<string> protocols_; |
| 199 | string name_; |
| 200 | vector<sp<IProtocolHandler>> remote_handlers_; |
| 201 | |
Casey Dahlin | f42e559 | 2016-03-02 14:09:10 -0800 | [diff] [blame] | 202 | // Map of local handler IDs to objects containing the various bits of IPC |
| 203 | // state we need to maintain those handlers on the remote end. |
| 204 | map<int,unique_ptr<RequestHandlerRegistration>> request_handler_ids_; |
Casey Dahlin | 730b0d5 | 2016-02-16 18:22:46 -0800 | [diff] [blame] | 205 | |
| 206 | DISALLOW_COPY_AND_ASSIGN(BinderProtocolHandler); |
| 207 | }; |
| 208 | |
Christopher Wiley | d6197ec | 2016-01-11 17:05:13 -0800 | [diff] [blame] | 209 | BinderServer::BinderServer(brillo::MessageLoop* message_loop, |
| 210 | const base::Closure& on_server_online, |
| 211 | const base::Closure& on_server_offline, |
| 212 | android::BinderWrapper* binder_wrapper) |
| 213 | : message_loop_{message_loop}, |
| 214 | on_server_online_{on_server_online}, |
| 215 | on_server_offline_{on_server_offline}, |
| 216 | binder_wrapper_{binder_wrapper} { |
| 217 | message_loop_->PostTask(FROM_HERE, |
| 218 | base::Bind(&BinderServer::TryConnecting, |
| 219 | weak_ptr_factory_.GetWeakPtr())); |
| 220 | } |
| 221 | |
| 222 | void BinderServer::TryConnecting() { |
| 223 | ClearLocalState(); |
Casey Dahlin | 242fa23 | 2016-02-17 17:01:55 -0800 | [diff] [blame] | 224 | sp<IBinder> binder = binder_wrapper_->GetService( |
Casey Dahlin | 24d0e75 | 2016-02-05 15:48:01 -0800 | [diff] [blame] | 225 | webservd::kWebserverBinderServiceName); |
Christopher Wiley | d6197ec | 2016-01-11 17:05:13 -0800 | [diff] [blame] | 226 | if (!binder.get()) { |
| 227 | LOG(INFO) << "Webservd has not registered with service manager."; |
| 228 | } else if (!BuildLocalState(binder)) { |
| 229 | ClearLocalState(); |
| 230 | } else { |
Casey Dahlin | cb64183 | 2016-03-11 15:12:31 -0800 | [diff] [blame] | 231 | if (!on_server_online_.is_null()) { |
| 232 | message_loop_->PostTask(FROM_HERE, on_server_online_); |
| 233 | } |
| 234 | |
Christopher Wiley | d6197ec | 2016-01-11 17:05:13 -0800 | [diff] [blame] | 235 | // Got a binder, built up appropriate local state, our job is done. |
| 236 | return; |
| 237 | } |
| 238 | message_loop_->PostDelayedTask(FROM_HERE, |
| 239 | base::Bind(&BinderServer::TryConnecting, |
| 240 | weak_ptr_factory_.GetWeakPtr()), |
| 241 | base::TimeDelta::FromSeconds(1)); |
| 242 | } |
| 243 | |
Christopher Wiley | d6197ec | 2016-01-11 17:05:13 -0800 | [diff] [blame] | 244 | void BinderServer::ClearLocalState() { |
Casey Dahlin | 730b0d5 | 2016-02-16 18:22:46 -0800 | [diff] [blame] | 245 | for (auto& local_handler: local_protocol_handlers_) { |
| 246 | local_handler.second->ResetRemoteProtocolHandlers(); |
Casey Dahlin | ef1354a | 2016-03-04 14:12:56 -0800 | [diff] [blame] | 247 | if (!on_protocol_handler_disconnected_.is_null()) { |
| 248 | message_loop_->PostTask( |
| 249 | FROM_HERE, base::Bind(on_protocol_handler_disconnected_, |
| 250 | base::Unretained(local_handler.second.get()))); |
| 251 | } |
Casey Dahlin | 730b0d5 | 2016-02-16 18:22:46 -0800 | [diff] [blame] | 252 | } |
Christopher Wiley | d6197ec | 2016-01-11 17:05:13 -0800 | [diff] [blame] | 253 | |
Casey Dahlin | cb64183 | 2016-03-11 15:12:31 -0800 | [diff] [blame] | 254 | if (remote_server_.get() && !on_server_offline_.is_null()) { |
| 255 | message_loop_->PostTask(FROM_HERE, on_server_offline_); |
| 256 | } |
Christopher Wiley | d6197ec | 2016-01-11 17:05:13 -0800 | [diff] [blame] | 257 | remote_server_.clear(); |
| 258 | } |
| 259 | |
Casey Dahlin | 242fa23 | 2016-02-17 17:01:55 -0800 | [diff] [blame] | 260 | bool BinderServer::BuildLocalState(sp<IBinder> server) { |
Christopher Wiley | d6197ec | 2016-01-11 17:05:13 -0800 | [diff] [blame] | 261 | remote_server_ = android::interface_cast<RemoteServer>(server); |
| 262 | vector<sp<IBinder>> remote_raw_binders; |
Casey Dahlin | f42e559 | 2016-03-02 14:09:10 -0800 | [diff] [blame] | 263 | if (!remote_server_->GetProtocolHandlers("", &remote_raw_binders).isOk()) { |
Christopher Wiley | d6197ec | 2016-01-11 17:05:13 -0800 | [diff] [blame] | 264 | // Possibly the server died, this is not necessarily an error. |
| 265 | LOG(INFO) << "Webservd failed to tell us about protocol handlers."; |
| 266 | return false; |
| 267 | } |
| 268 | |
| 269 | // Tell the local wrappers about the remote handlers that exist now. |
| 270 | for (auto& raw_binder: remote_raw_binders) { |
| 271 | sp<RemoteProtocolHandler> remote_handler = |
| 272 | android::interface_cast<RemoteProtocolHandler>(raw_binder); |
Casey Dahlin | 820d997 | 2016-02-03 15:08:41 -0800 | [diff] [blame] | 273 | string name; |
Christopher Wiley | d6197ec | 2016-01-11 17:05:13 -0800 | [diff] [blame] | 274 | if (!remote_handler->GetName(&name).isOk()) { |
| 275 | LOG(INFO) << "Remote handler could not report its name."; |
| 276 | return false; |
| 277 | } |
Casey Dahlin | 730b0d5 | 2016-02-16 18:22:46 -0800 | [diff] [blame] | 278 | |
| 279 | auto it = local_protocol_handlers_.find(name); |
| 280 | |
| 281 | if (it == local_protocol_handlers_.end()) { |
| 282 | unique_ptr<BinderProtocolHandler> local_handler( |
| 283 | new BinderProtocolHandler(name)); |
Casey Dahlin | f42e559 | 2016-03-02 14:09:10 -0800 | [diff] [blame] | 284 | it = local_protocol_handlers_.emplace(name, |
| 285 | std::move(local_handler)).first; |
Casey Dahlin | 730b0d5 | 2016-02-16 18:22:46 -0800 | [diff] [blame] | 286 | } |
| 287 | |
| 288 | it->second->AddRemote(remote_handler); |
Casey Dahlin | ef1354a | 2016-03-04 14:12:56 -0800 | [diff] [blame] | 289 | if (!on_protocol_handler_connected_.is_null()) { |
| 290 | message_loop_->PostTask(FROM_HERE, |
| 291 | base::Bind(on_protocol_handler_connected_, |
| 292 | base::Unretained(it->second.get()))); |
| 293 | } |
Christopher Wiley | d6197ec | 2016-01-11 17:05:13 -0800 | [diff] [blame] | 294 | } |
| 295 | return true; |
| 296 | } |
| 297 | |
Casey Dahlin | 33d72c0 | 2016-02-05 11:24:02 -0800 | [diff] [blame] | 298 | ProtocolHandler* BinderServer::GetDefaultHttpHandler() { |
| 299 | return GetProtocolHandler(ProtocolHandler::kHttp); |
| 300 | } |
| 301 | |
| 302 | ProtocolHandler* BinderServer::GetDefaultHttpsHandler() { |
| 303 | return GetProtocolHandler(ProtocolHandler::kHttps); |
| 304 | } |
| 305 | |
Casey Dahlin | 730b0d5 | 2016-02-16 18:22:46 -0800 | [diff] [blame] | 306 | ProtocolHandler* BinderServer::GetProtocolHandler(const string& name) { |
| 307 | auto it = local_protocol_handlers_.find(name); |
| 308 | |
| 309 | if (it == local_protocol_handlers_.end()) { |
Casey Dahlin | f42e559 | 2016-03-02 14:09:10 -0800 | [diff] [blame] | 310 | unique_ptr<BinderProtocolHandler> local_handler( |
| 311 | new BinderProtocolHandler(name)); |
| 312 | it = local_protocol_handlers_.emplace(name, |
| 313 | std::move(local_handler)).first; |
Casey Dahlin | 730b0d5 | 2016-02-16 18:22:46 -0800 | [diff] [blame] | 314 | } |
| 315 | |
| 316 | return it->second.get(); |
Casey Dahlin | 33d72c0 | 2016-02-05 11:24:02 -0800 | [diff] [blame] | 317 | } |
| 318 | |
| 319 | bool BinderServer::IsConnected() const { |
| 320 | return remote_server_.get() != nullptr; |
| 321 | } |
| 322 | |
| 323 | void BinderServer::OnProtocolHandlerConnected( |
Casey Dahlin | ef1354a | 2016-03-04 14:12:56 -0800 | [diff] [blame] | 324 | const base::Callback<void(ProtocolHandler*)>& callback) { |
| 325 | on_protocol_handler_connected_ = callback; |
| 326 | |
| 327 | for (auto& handler : local_protocol_handlers_) { |
| 328 | if (handler.second->IsConnected()) { |
| 329 | message_loop_->PostTask( |
| 330 | FROM_HERE, |
| 331 | base::Bind(callback, base::Unretained(handler.second.get()))); |
| 332 | } |
| 333 | } |
Casey Dahlin | 33d72c0 | 2016-02-05 11:24:02 -0800 | [diff] [blame] | 334 | } |
| 335 | |
| 336 | void BinderServer::OnProtocolHandlerDisconnected( |
Casey Dahlin | ef1354a | 2016-03-04 14:12:56 -0800 | [diff] [blame] | 337 | const base::Callback<void(ProtocolHandler*)>& callback) { |
| 338 | on_protocol_handler_disconnected_ = callback; |
Casey Dahlin | 33d72c0 | 2016-02-05 11:24:02 -0800 | [diff] [blame] | 339 | |
Casey Dahlin | ef1354a | 2016-03-04 14:12:56 -0800 | [diff] [blame] | 340 | for (auto& handler : local_protocol_handlers_) { |
| 341 | if (!handler.second->IsConnected()) { |
| 342 | message_loop_->PostTask( |
| 343 | FROM_HERE, |
| 344 | base::Bind(callback, base::Unretained(handler.second.get()))); |
| 345 | } |
| 346 | } |
Casey Dahlin | 33d72c0 | 2016-02-05 11:24:02 -0800 | [diff] [blame] | 347 | } |
| 348 | |
| 349 | base::TimeDelta BinderServer::GetDefaultRequestTimeout() const { |
Casey Dahlin | 2f69b81 | 2016-02-16 14:10:48 -0800 | [diff] [blame] | 350 | int32_t timeout_seconds; |
| 351 | if (!remote_server_->GetDefaultRequestTimeout(&timeout_seconds).isOk()) { |
| 352 | LOG(ERROR) << "Could not get request timeout from remote server."; |
| 353 | |
| 354 | // Precedent from the DBus server says this is the error return value. |
| 355 | return base::TimeDelta::Max(); |
| 356 | } |
| 357 | |
| 358 | return base::TimeDelta::FromSeconds(timeout_seconds); |
Casey Dahlin | 33d72c0 | 2016-02-05 11:24:02 -0800 | [diff] [blame] | 359 | } |
| 360 | |
Christopher Wiley | d6197ec | 2016-01-11 17:05:13 -0800 | [diff] [blame] | 361 | } // namespace libwebserv |