Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(303)

Unified Diff: remoting/host/elevated_controller_win.cc

Issue 9953002: The me2me host is now configurable from the web UI on Windows. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: CR feedback Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: remoting/host/elevated_controller_win.cc
diff --git a/remoting/host/elevated_controller_win.cc b/remoting/host/elevated_controller_win.cc
index 708bed29f74a240cd0aeb60d4cdd150359838128..aad59ba7ec7e83050ee6174119e970658e63e2b0 100644
--- a/remoting/host/elevated_controller_win.cc
+++ b/remoting/host/elevated_controller_win.cc
@@ -4,11 +4,87 @@
#include "remoting/host/elevated_controller_win.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/path_service.h"
+#include "base/utf_string_conversions.h"
+#include "base/values.h"
+#include "base/win/scoped_handle.h"
+#include "remoting/host/branding.h"
+
// MIDL-generated definitions.
-#include <elevated_controller_i.c>
+#include "elevated_controller_i.c"
+
+namespace {
+
+// TODO(alexeypa): remove this limitation.
+const size_t kMaxConfigFileSize = 0x10000;
Wez 2012/03/30 22:11:01 nit: Specifying the max file size in hex makes it
alexeypa (please no reviews) 2012/03/30 23:47:09 Done.
+
+const char kHostId[] = "host_id";
+const char kXmppLogin[] = "xmpp_login";
Wez 2012/03/30 22:11:01 nit: Add a comment to explain what these constants
alexeypa (please no reviews) 2012/03/30 23:47:09 Done.
+
+// Names of the configuration files.
+const FilePath::CharType kAuthConfig[] = FILE_PATH_LITERAL("auth.json");
Wez 2012/03/30 22:11:01 nit: These should really be kAuthConfig -> kAuthCo
alexeypa (please no reviews) 2012/03/30 23:47:09 Done.
+const FilePath::CharType kHostConfig[] = FILE_PATH_LITERAL("host.json");
+
+// TODO(alexeypa): remove the hardcoded undocimented paths and store
Wez 2012/03/30 22:11:01 typos: remove -> Remove, undocimented.
alexeypa (please no reviews) 2012/03/30 23:47:09 Done.
+// the configuration in the registry.
+#ifdef OFFICIAL_BUILD
+const FilePath::CharType kConfigDir[] = FILE_PATH_LITERAL(
+ "config\\systemprofile\\AppData\\Local\\Google\\Chrome Remote Desktop");
+#else
+const FilePath::CharType kConfigDir[] =
+ FILE_PATH_LITERAL("config\\systemprofile\\AppData\\Local\\Chromoting");
+#endif
+
+// Reads and parses a JSON configuration file (up to 64KB in size).
Wez 2012/03/30 22:11:01 nit: The "up to 64KB in size" comment goes with th
alexeypa (please no reviews) 2012/03/30 23:47:09 Done.
+HRESULT ReadConfig(const FilePath& filename,
+ scoped_ptr<base::DictionaryValue>* config_out) {
+ // Read raw data from the configuration file.
+ base::win::ScopedHandle file(
+ CreateFileW(filename.value().c_str(),
+ GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_SEQUENTIAL_SCAN,
+ NULL));
+
+ if (!file.IsValid()) {
+ DWORD error = GetLastError();
+ LOG_GETLASTERROR(ERROR)
+ << "Failed to read '" << filename.value() << "'";
+ return HRESULT_FROM_WIN32(error);
+ }
+
+ std::vector<char> buffer(kMaxConfigFileSize);
+ DWORD size = static_cast<DWORD>(buffer.size());
+ if (!::ReadFile(file, &buffer[0], size, &size, NULL)) {
+ DWORD error = GetLastError();
+ LOG_GETLASTERROR(ERROR)
+ << "Failed to read '" << filename.value() << "'";
+ return HRESULT_FROM_WIN32(error);
+ }
-using ATL::CComQIPtr;
-using ATL::CComPtr;
+ // Parse JSON data.
Wez 2012/03/30 22:11:01 nit: "Parse the JSON configuration, expecting it t
alexeypa (please no reviews) 2012/03/30 23:47:09 Done.
+ std::string file_content(&buffer[0], size);
+ scoped_ptr<base::Value> value(base::JSONReader::Read(file_content, true));
+
+ base::DictionaryValue* dictionary;
+ if (value.get() == NULL || !value->GetAsDictionary(&dictionary)) {
+ LOG(ERROR) << "Failed to read '" << filename.value() << "'.";
+ return E_FAIL;
+ }
+
+ value.release();
+ config_out->reset(dictionary);
Wez 2012/03/30 22:11:01 Gah. Gross. Can't see a better way to do it, off
+ return S_OK;
+}
+
+} // namespace
namespace remoting {
@@ -22,52 +98,143 @@ HRESULT ElevatedControllerWin::FinalConstruct() {
void ElevatedControllerWin::FinalRelease() {
}
-STDMETHODIMP ElevatedControllerWin::get_State(DaemonState* state_out) {
- return E_NOTIMPL;
-}
+STDMETHODIMP ElevatedControllerWin::GetConfig(BSTR* config_out) {
+ FilePath system_profile;
+ PathService::Get(base::DIR_SYSTEM, &system_profile);
+
+ // Build the host configuration.
Wez 2012/03/30 22:11:01 nit: Isn't this reading it, rather than "building"
alexeypa (please no reviews) 2012/03/30 23:47:09 Done.
+ scoped_ptr<base::DictionaryValue> config;
+ HRESULT hr = ReadConfig(system_profile.Append(kConfigDir).Append(kHostConfig),
+ &config);
+ if (FAILED(hr)) {
+ return hr;
+ }
-STDMETHODIMP ElevatedControllerWin::ReadConfig(BSTR* config_out) {
- return E_NOTIMPL;
+ // Build the filtered config.
Wez 2012/03/30 22:11:01 Why? What is the purpose of the filtering?
alexeypa (please no reviews) 2012/03/30 23:47:09 This matched Mac implementation.
Lambros 2012/03/31 00:48:34 GetConfig() is documented to return only certain k
Wez 2012/04/01 01:25:27 Right; my point is that the comment should clarify
alexeypa (please no reviews) 2012/04/02 16:26:39 Oh, well. I'll try to address this in one of the f
+ scoped_ptr<base::DictionaryValue> filtered_config(
+ new base::DictionaryValue());
+
+ std::string value;
+ if (config->GetString(kHostId, &value)) {
+ filtered_config->SetString(kHostId, value);
+ }
+
Wez 2012/03/30 22:11:01 nit: No need for this blank line.
alexeypa (please no reviews) 2012/03/30 23:47:09 Done.
+ if (config->GetString(kXmppLogin, &value)) {
+ filtered_config->SetString(kXmppLogin, value);
+ }
+
+ // Convert the filtered config back to string and return it to the caller.
Wez 2012/03/30 22:11:01 typo: ... back to a string ...
alexeypa (please no reviews) 2012/03/30 23:47:09 Done.
+ std::string file_content;
+ base::JSONWriter::Write(filtered_config.get(), &file_content);
+
+ *config_out = ::SysAllocString(UTF8ToUTF16(file_content).c_str());
+ if (config_out == NULL) {
+ return E_OUTOFMEMORY;
+ }
+
+ return S_OK;
}
-STDMETHODIMP ElevatedControllerWin::WriteConfig(BSTR config) {
- return E_NOTIMPL;
+STDMETHODIMP ElevatedControllerWin::SetConfig(BSTR config) {
+ FilePath system_profile;
Wez 2012/03/30 22:11:01 nit: Comment before these lines e.g. "Determine th
alexeypa (please no reviews) 2012/03/30 23:47:09 Done.
+ PathService::Get(base::DIR_SYSTEM, &system_profile);
+
Wez 2012/03/30 22:11:01 nit: No need for this blank line?
alexeypa (please no reviews) 2012/03/30 23:47:09 Removed. My eyes hurt now! :-)
+ FilePath config_dir = system_profile.Append(kConfigDir);
+ if (!file_util::CreateDirectory(config_dir)) {
+ return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
+ }
+
+ std::string file_content = UTF16ToUTF8(
+ string16(static_cast<char16*>(config), ::SysStringLen(config)));
+
+ int written = file_util::WriteFile(
Wez 2012/03/30 22:11:01 Should we be doing the write-temp-file-then-delete
alexeypa (please no reviews) 2012/03/30 23:47:09 We could. However the whole configuration flow is
+ config_dir.Append(kAuthConfig),
+ file_content.c_str(),
+ file_content.size());
+
+ if (written != static_cast<int>(file_content.size())) {
+ return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
+ }
+
+ // TODO(alexeypa): make it a single file.
Wez 2012/03/30 22:11:01 nit: I think you mean "Store the authentication an
alexeypa (please no reviews) 2012/03/30 23:47:09 Done.
+ written = file_util::WriteFile(
+ config_dir.Append(kHostConfig),
+ file_content.c_str(),
+ file_content.size());
+
+ if (written != static_cast<int>(file_content.size())) {
+ return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
Wez 2012/03/30 22:11:01 nit: That's not strictly the right error, and in f
alexeypa (please no reviews) 2012/03/30 23:47:09 Nope. I bet something else bad happened. I replace
+ }
+
+ return S_OK;
}
STDMETHODIMP ElevatedControllerWin::StartDaemon() {
- return E_NOTIMPL;
-}
+ ScopedScHandle service;
+ HRESULT hr = OpenService(&service);
+ if (FAILED(hr)) {
+ return hr;
+ }
-STDMETHODIMP ElevatedControllerWin::StopDaemon() {
- return E_NOTIMPL;
+ if (!StartService(service, 0, NULL)) {
+ DWORD error = GetLastError();
+ if (error != ERROR_SERVICE_ALREADY_RUNNING) {
+ LOG_GETLASTERROR(ERROR)
+ << "Failed to start the '" << kWindowsServiceName << "'service";
+
+ return HRESULT_FROM_WIN32(error);
+ }
+ }
+
+ return S_OK;
}
-HRESULT ElevatedControllerWin::FireOnStateChange(DaemonState state) {
- CComPtr<IConnectionPoint> connection_point;
- FindConnectionPoint(__uuidof(IDaemonEvents), &connection_point);
- if (!connection_point) {
- return S_OK;
+STDMETHODIMP ElevatedControllerWin::StopDaemon() {
+ ScopedScHandle service;
+ HRESULT hr = OpenService(&service);
+ if (FAILED(hr)) {
+ return hr;
Wez 2012/03/30 22:11:01 Do you actually want to return potentially arbitra
alexeypa (please no reviews) 2012/03/30 23:47:09 I don't think so. Something better defined is "ope
Wez 2012/04/01 01:25:27 The word "here" was missing from my sentence; I th
alexeypa (please no reviews) 2012/04/02 16:26:39 That is not the only reason. I don't think that us
}
- CComPtr<IEnumConnections> connections;
- if (FAILED(connection_point->EnumConnections(&connections))) {
- return S_OK;
+ SERVICE_STATUS status;
+ if (!ControlService(service, SERVICE_CONTROL_STOP, &status)) {
+ DWORD error = GetLastError();
+ if (error != ERROR_SERVICE_NOT_ACTIVE) {
+ LOG_GETLASTERROR(ERROR)
+ << "Failed to stop the '" << kWindowsServiceName << "'service";
+ return HRESULT_FROM_WIN32(error);
+ }
}
- CONNECTDATA connect_data;
- while (connections->Next(1, &connect_data, NULL) == S_OK) {
- if (connect_data.pUnk != NULL) {
- CComQIPtr<IDaemonEvents, &__uuidof(IDaemonEvents)> sink(
- connect_data.pUnk);
+ return S_OK;
+}
+
+HRESULT ElevatedControllerWin::OpenService(ScopedScHandle* service_out) {
+ DWORD error;
- if (sink != NULL) {
- sink->OnStateChange(state);
- }
+ ScopedScHandle scmanager(
+ ::OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASE,
+ SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE));
+ if (!scmanager.IsValid()) {
+ error = GetLastError();
+ LOG_GETLASTERROR(ERROR)
+ << "Failed to connect to the service control manager";
- connect_data.pUnk->Release();
- }
+ return HRESULT_FROM_WIN32(error);
+ }
+
+ ScopedScHandle service(
+ ::OpenServiceA(scmanager, kWindowsServiceName,
Wez 2012/03/30 22:11:01 nit: Why are we using OpenServiceA but OpenSCManag
alexeypa (please no reviews) 2012/03/30 23:47:09 Done.
+ SERVICE_QUERY_STATUS | SERVICE_START | SERVICE_STOP));
+ if (!service.IsValid()) {
+ error = GetLastError();
+ LOG_GETLASTERROR(ERROR)
+ << "Failed to open to the '" << kWindowsServiceName << "' service";
+
+ return HRESULT_FROM_WIN32(error);
}
+ service_out->Set(service.Take());
return S_OK;
}

Powered by Google App Engine
This is Rietveld 408576698