1 // Copyright 2015 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 
15 #include "webservd/dbus_protocol_handler.h"
16 
17 #include <base/bind.h>
18 #include <brillo/dbus/async_event_sequencer.h>
19 #include <brillo/dbus/exported_object_manager.h>
20 
21 #include "webservd/dbus_request_handler.h"
22 #include "webservd/protocol_handler.h"
23 #include "webservd/request.h"
24 #include "webservd/server.h"
25 
26 using brillo::dbus_utils::AsyncEventSequencer;
27 using brillo::dbus_utils::DBusObject;
28 using brillo::dbus_utils::ExportedObjectManager;
29 
30 namespace webservd {
31 
DBusProtocolHandler(ExportedObjectManager * object_manager,const dbus::ObjectPath & object_path,ProtocolHandler * protocol_handler,Server * server)32 DBusProtocolHandler::DBusProtocolHandler(
33     ExportedObjectManager* object_manager,
34     const dbus::ObjectPath& object_path,
35     ProtocolHandler* protocol_handler,
36     Server* server)
37     : dbus_object_{new DBusObject{object_manager, object_manager->GetBus(),
38                                   object_path}},
39       protocol_handler_{protocol_handler},
40       server_{server} {
41   dbus_adaptor_.SetId(protocol_handler->GetID());
42   dbus_adaptor_.SetName(protocol_handler->GetName());
43   dbus_adaptor_.SetPort(protocol_handler->GetPort());
44   dbus_adaptor_.SetProtocol(protocol_handler->GetProtocol());
45   dbus_adaptor_.SetCertificateFingerprint(
46       protocol_handler->GetCertificateFingerprint());
47 }
48 
~DBusProtocolHandler()49 DBusProtocolHandler::~DBusProtocolHandler() {
50   for (const auto& pair : dbus_service_data_) {
51     server_->GetBus()->UnlistenForServiceOwnerChange(
52         pair.first, pair.second.on_client_disconnected_callback);
53   }
54 }
55 
RegisterAsync(const AsyncEventSequencer::CompletionAction & completion_callback)56 void DBusProtocolHandler::RegisterAsync(
57     const AsyncEventSequencer::CompletionAction& completion_callback) {
58   scoped_refptr<AsyncEventSequencer> sequencer(new AsyncEventSequencer());
59   dbus_adaptor_.RegisterWithDBusObject(dbus_object_.get());
60   dbus_object_->RegisterAsync(
61       sequencer->GetHandler("Failed exporting ProtocolHandler.", true));
62   sequencer->OnAllTasksCompletedCall({completion_callback});
63 }
64 
GetObjectManager() const65 ExportedObjectManager* DBusProtocolHandler::GetObjectManager() const {
66   return dbus_object_->GetObjectManager().get();
67 }
68 
AddRequestHandler(brillo::ErrorPtr *,dbus::Message * message,const std::string & in_url,const std::string & in_method,const std::string & in_service_name,std::string * out_request_handler_id)69 bool DBusProtocolHandler::AddRequestHandler(
70     brillo::ErrorPtr* /* error */,
71     dbus::Message* message,
72     const std::string& in_url,
73     const std::string& in_method,
74     const std::string& in_service_name,
75     std::string* out_request_handler_id) {
76   auto p = dbus_service_data_.find(in_service_name);
77   if (p == dbus_service_data_.end()) {
78     DBusServiceData dbus_service_data;
79     dbus_service_data.owner = message->GetSender();
80     dbus_service_data.handler_proxy.reset(
81         new RequestHandlerProxy{server_->GetBus(), in_service_name});
82     dbus_service_data.on_client_disconnected_callback =
83         base::Bind(&DBusProtocolHandler::OnClientDisconnected,
84                    weak_ptr_factory_.GetWeakPtr(),
85                    in_service_name);
86     server_->GetBus()->ListenForServiceOwnerChange(
87         in_service_name, dbus_service_data.on_client_disconnected_callback);
88     p = dbus_service_data_.emplace(in_service_name,
89                                    std::move(dbus_service_data)).first;
90   }
91   std::unique_ptr<RequestHandlerInterface> handler{
92     new DBusRequestHandler{server_, p->second.handler_proxy.get()}
93   };
94   std::string handler_id = protocol_handler_->AddRequestHandler(
95       in_url, in_method, std::move(handler));
96   p->second.handler_ids.insert(handler_id);
97   handler_to_service_name_map_.emplace(handler_id, in_service_name);
98 
99   *out_request_handler_id = handler_id;
100   return true;
101 }
102 
RemoveRequestHandler(brillo::ErrorPtr * error,const std::string & in_handler_id)103 bool DBusProtocolHandler::RemoveRequestHandler(
104     brillo::ErrorPtr* error,
105     const std::string& in_handler_id) {
106 
107   auto p = handler_to_service_name_map_.find(in_handler_id);
108   if (p == handler_to_service_name_map_.end()) {
109     brillo::Error::AddToPrintf(error,
110                                FROM_HERE,
111                                brillo::errors::dbus::kDomain,
112                                DBUS_ERROR_FAILED,
113                                "Handler with ID %s does not exist",
114                                in_handler_id.c_str());
115     return false;
116   }
117   std::string service_name = p->second;
118   CHECK(protocol_handler_->RemoveRequestHandler(in_handler_id));
119   DBusServiceData& dbus_service_data = dbus_service_data_[service_name];
120   CHECK_EQ(1u, dbus_service_data.handler_ids.erase(in_handler_id));
121   if (dbus_service_data.handler_ids.empty()) {
122     server_->GetBus()->UnlistenForServiceOwnerChange(
123         service_name, dbus_service_data.on_client_disconnected_callback);
124     dbus_service_data_.erase(service_name);
125   }
126   return true;
127 }
128 
OnClientDisconnected(const std::string & service_name,const std::string & service_owner)129 void DBusProtocolHandler::OnClientDisconnected(
130     const std::string& service_name,
131     const std::string& service_owner) {
132   // This method will be called when the client's D-Bus service owner has
133   // changed which could be either the client exiting (|service_owner| is empty)
134   // or is being replaced with another running instance.
135   // In either case, we need to remove the old client's handlers since the
136   // new client will register their own on start up anyway.
137   // However pay attention to the case where the service owner is the same as
138   // the sender, in which case we should not remove the handlers. This happens
139   // if the handling process claims D-Bus service after it registers request
140   // handlers with the web server.
141   auto p = dbus_service_data_.find(service_name);
142   if (p == dbus_service_data_.end() || p->second.owner == service_owner)
143     return;
144 
145   for (const std::string& handler_id : p->second.handler_ids) {
146     handler_to_service_name_map_.erase(handler_id);
147     protocol_handler_->RemoveRequestHandler(handler_id);
148   }
149   server_->GetBus()->UnlistenForServiceOwnerChange(
150       service_name, p->second.on_client_disconnected_callback);
151   dbus_service_data_.erase(p);
152 }
153 
GetRequestFileData(brillo::ErrorPtr * error,const std::string & in_request_id,int32_t in_file_id,dbus::FileDescriptor * out_contents)154 bool DBusProtocolHandler::GetRequestFileData(
155     brillo::ErrorPtr* error,
156     const std::string& in_request_id,
157     int32_t in_file_id,
158     dbus::FileDescriptor* out_contents) {
159   auto request = GetRequest(in_request_id, error);
160   if (!request)
161     return false;
162 
163   base::File file = request->GetFileData(in_file_id);
164   if (file.IsValid()) {
165     out_contents->PutValue(file.TakePlatformFile());
166     out_contents->CheckValidity();
167     return true;
168   }
169 
170   brillo::Error::AddToPrintf(error,
171                              FROM_HERE,
172                              brillo::errors::dbus::kDomain,
173                              DBUS_ERROR_FAILED,
174                              "File with ID %d does not exist",
175                              in_file_id);
176   return false;
177 }
178 
CompleteRequest(brillo::ErrorPtr * error,const std::string & in_request_id,int32_t in_status_code,const std::vector<std::tuple<std::string,std::string>> & in_headers,int64_t in_data_size,dbus::FileDescriptor * out_response_stream)179 bool DBusProtocolHandler::CompleteRequest(
180     brillo::ErrorPtr* error,
181     const std::string& in_request_id,
182     int32_t in_status_code,
183     const std::vector<std::tuple<std::string, std::string>>& in_headers,
184     int64_t in_data_size,
185     dbus::FileDescriptor* out_response_stream) {
186   auto request = GetRequest(in_request_id, error);
187   if (!request)
188     return false;
189 
190   base::File file = request->Complete(in_status_code, in_headers, in_data_size);
191   if (file.IsValid()) {
192     out_response_stream->PutValue(file.TakePlatformFile());
193     out_response_stream->CheckValidity();
194     return true;
195   }
196   brillo::Error::AddTo(error, FROM_HERE, brillo::errors::dbus::kDomain,
197                        DBUS_ERROR_FAILED, "Response already received");
198   return false;
199 }
200 
GetRequest(const std::string & request_id,brillo::ErrorPtr * error)201 Request* DBusProtocolHandler::GetRequest(const std::string& request_id,
202                                          brillo::ErrorPtr* error) {
203   Request* request = protocol_handler_->GetRequest(request_id);
204   if (!request) {
205     brillo::Error::AddToPrintf(error,
206                                FROM_HERE,
207                                brillo::errors::dbus::kDomain,
208                                DBUS_ERROR_FAILED,
209                                "Unknown request ID: %s",
210                                request_id.c_str());
211   }
212   return request;
213 }
214 
215 }  // namespace webservd
216