| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "remoting/host/plugin/daemon_controller.h" | 5 #include "remoting/host/plugin/daemon_controller.h" |
| 6 | 6 |
| 7 #include <launch.h> | 7 #include <launch.h> |
| 8 #include <stdio.h> | 8 #include <stdio.h> |
| 9 #include <sys/types.h> | 9 #include <sys/types.h> |
| 10 | 10 |
| (...skipping 19 matching lines...) Expand all Loading... |
| 30 namespace remoting { | 30 namespace remoting { |
| 31 | 31 |
| 32 namespace { | 32 namespace { |
| 33 | 33 |
| 34 // The NSSystemDirectories.h header has a conflicting definition of | 34 // The NSSystemDirectories.h header has a conflicting definition of |
| 35 // NSSearchPathDirectory with the one in base/mac/foundation_util.h. | 35 // NSSearchPathDirectory with the one in base/mac/foundation_util.h. |
| 36 // Foundation.h would work, but it can only be included from Objective-C files. | 36 // Foundation.h would work, but it can only be included from Objective-C files. |
| 37 // Therefore, we define the needed constants here. | 37 // Therefore, we define the needed constants here. |
| 38 const int NSLibraryDirectory = 5; | 38 const int NSLibraryDirectory = 5; |
| 39 | 39 |
| 40 // Use a single configuration file, instead of separate "auth" and "host" files. | |
| 41 // This is because the SetConfigAndStart() API only provides a single | |
| 42 // dictionary, and splitting this into two dictionaries would require | |
| 43 // knowledge of which keys belong in which files. | |
| 44 const char kHostConfigFile[] = kHostConfigDir kServiceName ".json"; | |
| 45 | |
| 46 class DaemonControllerMac : public remoting::DaemonController { | 40 class DaemonControllerMac : public remoting::DaemonController { |
| 47 public: | 41 public: |
| 48 DaemonControllerMac(); | 42 DaemonControllerMac(); |
| 49 virtual ~DaemonControllerMac(); | 43 virtual ~DaemonControllerMac(); |
| 50 | 44 |
| 51 virtual State GetState() OVERRIDE; | 45 virtual State GetState() OVERRIDE; |
| 52 virtual void GetConfig(const GetConfigCallback& callback) OVERRIDE; | 46 virtual void GetConfig(const GetConfigCallback& callback) OVERRIDE; |
| 53 virtual void SetConfigAndStart( | 47 virtual void SetConfigAndStart( |
| 54 scoped_ptr<base::DictionaryValue> config, | 48 scoped_ptr<base::DictionaryValue> config, |
| 55 bool consent, | 49 bool consent, |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 97 | 91 |
| 98 DaemonControllerMac::~DaemonControllerMac() { | 92 DaemonControllerMac::~DaemonControllerMac() { |
| 99 auth_thread_.Stop(); | 93 auth_thread_.Stop(); |
| 100 DeregisterForPreferencePaneNotifications(); | 94 DeregisterForPreferencePaneNotifications(); |
| 101 } | 95 } |
| 102 | 96 |
| 103 void DaemonControllerMac::DeregisterForPreferencePaneNotifications() { | 97 void DaemonControllerMac::DeregisterForPreferencePaneNotifications() { |
| 104 CFNotificationCenterRemoveObserver( | 98 CFNotificationCenterRemoveObserver( |
| 105 CFNotificationCenterGetDistributedCenter(), | 99 CFNotificationCenterGetDistributedCenter(), |
| 106 this, | 100 this, |
| 107 CFSTR(kUpdateSucceededNotificationName), | 101 CFSTR(UPDATE_SUCCEEDED_NOTIFICATION_NAME), |
| 108 NULL); | 102 NULL); |
| 109 CFNotificationCenterRemoveObserver( | 103 CFNotificationCenterRemoveObserver( |
| 110 CFNotificationCenterGetDistributedCenter(), | 104 CFNotificationCenterGetDistributedCenter(), |
| 111 this, | 105 this, |
| 112 CFSTR(kUpdateFailedNotificationName), | 106 CFSTR(UPDATE_FAILED_NOTIFICATION_NAME), |
| 113 NULL); | 107 NULL); |
| 114 } | 108 } |
| 115 | 109 |
| 116 DaemonController::State DaemonControllerMac::GetState() { | 110 DaemonController::State DaemonControllerMac::GetState() { |
| 117 if (!base::mac::IsOSSnowLeopardOrLater()) { | 111 if (!base::mac::IsOSSnowLeopardOrLater()) { |
| 118 return DaemonController::STATE_NOT_IMPLEMENTED; | 112 return DaemonController::STATE_NOT_IMPLEMENTED; |
| 119 } | 113 } |
| 120 pid_t job_pid = base::mac::PIDForJob(kServiceName); | 114 pid_t job_pid = base::mac::PIDForJob(kServiceName); |
| 121 if (job_pid < 0) { | 115 if (job_pid < 0) { |
| 122 return DaemonController::STATE_NOT_INSTALLED; | 116 return DaemonController::STATE_NOT_INSTALLED; |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 173 } | 167 } |
| 174 | 168 |
| 175 void DaemonControllerMac::GetUsageStatsConsent( | 169 void DaemonControllerMac::GetUsageStatsConsent( |
| 176 const GetUsageStatsConsentCallback& callback) { | 170 const GetUsageStatsConsentCallback& callback) { |
| 177 // Crash dump collection is not implemented on Mac yet. | 171 // Crash dump collection is not implemented on Mac yet. |
| 178 // http://crbug.com/130678. | 172 // http://crbug.com/130678. |
| 179 callback.Run(false, false, false); | 173 callback.Run(false, false, false); |
| 180 } | 174 } |
| 181 | 175 |
| 182 void DaemonControllerMac::DoGetConfig(const GetConfigCallback& callback) { | 176 void DaemonControllerMac::DoGetConfig(const GetConfigCallback& callback) { |
| 183 FilePath config_path(kHostConfigFile); | 177 FilePath config_path(kHostConfigFilePath); |
| 184 JsonHostConfig host_config(config_path); | 178 JsonHostConfig host_config(config_path); |
| 185 scoped_ptr<base::DictionaryValue> config; | 179 scoped_ptr<base::DictionaryValue> config; |
| 186 | 180 |
| 187 if (host_config.Read()) { | 181 if (host_config.Read()) { |
| 188 config.reset(new base::DictionaryValue()); | 182 config.reset(new base::DictionaryValue()); |
| 189 std::string value; | 183 std::string value; |
| 190 if (host_config.GetString(kHostIdConfigPath, &value)) | 184 if (host_config.GetString(kHostIdConfigPath, &value)) |
| 191 config.get()->SetString(kHostIdConfigPath, value); | 185 config.get()->SetString(kHostIdConfigPath, value); |
| 192 if (host_config.GetString(kXmppLoginConfigPath, &value)) | 186 if (host_config.GetString(kXmppLoginConfigPath, &value)) |
| 193 config.get()->SetString(kXmppLoginConfigPath, value); | 187 config.get()->SetString(kXmppLoginConfigPath, value); |
| 194 } | 188 } |
| 195 | 189 |
| 196 callback.Run(config.Pass()); | 190 callback.Run(config.Pass()); |
| 197 } | 191 } |
| 198 | 192 |
| 199 void DaemonControllerMac::DoGetVersion(const GetVersionCallback& callback) { | 193 void DaemonControllerMac::DoGetVersion(const GetVersionCallback& callback) { |
| 200 std::string version = ""; | 194 std::string version = ""; |
| 201 std::string command_line = remoting::kHostHelperTool; | 195 std::string command_line = remoting::kHostHelperScriptPath; |
| 202 command_line += " --host-version"; | 196 command_line += " --host-version"; |
| 203 FILE* script_output = popen(command_line.c_str(), "r"); | 197 FILE* script_output = popen(command_line.c_str(), "r"); |
| 204 if (script_output) { | 198 if (script_output) { |
| 205 char buffer[100]; | 199 char buffer[100]; |
| 206 char* result = fgets(buffer, sizeof(buffer), script_output); | 200 char* result = fgets(buffer, sizeof(buffer), script_output); |
| 207 pclose(script_output); | 201 pclose(script_output); |
| 208 if (result) { | 202 if (result) { |
| 209 // The string is guaranteed to be null-terminated, but probably contains | 203 // The string is guaranteed to be null-terminated, but probably contains |
| 210 // a newline character, which we don't want. | 204 // a newline character, which we don't want. |
| 211 for (int i = 0; result[i]; ++i) { | 205 for (int i = 0; result[i]; ++i) { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 224 scoped_ptr<base::DictionaryValue> config, | 218 scoped_ptr<base::DictionaryValue> config, |
| 225 const CompletionCallback& done) { | 219 const CompletionCallback& done) { |
| 226 std::string config_data; | 220 std::string config_data; |
| 227 base::JSONWriter::Write(config.get(), &config_data); | 221 base::JSONWriter::Write(config.get(), &config_data); |
| 228 ShowPreferencePane(config_data, done); | 222 ShowPreferencePane(config_data, done); |
| 229 } | 223 } |
| 230 | 224 |
| 231 void DaemonControllerMac::DoUpdateConfig( | 225 void DaemonControllerMac::DoUpdateConfig( |
| 232 scoped_ptr<base::DictionaryValue> config, | 226 scoped_ptr<base::DictionaryValue> config, |
| 233 const CompletionCallback& done_callback) { | 227 const CompletionCallback& done_callback) { |
| 234 FilePath config_file_path(kHostConfigFile); | 228 FilePath config_file_path(kHostConfigFilePath); |
| 235 JsonHostConfig config_file(config_file_path); | 229 JsonHostConfig config_file(config_file_path); |
| 236 if (!config_file.Read()) { | 230 if (!config_file.Read()) { |
| 237 done_callback.Run(RESULT_FAILED); | 231 done_callback.Run(RESULT_FAILED); |
| 238 return; | 232 return; |
| 239 } | 233 } |
| 240 for (DictionaryValue::key_iterator key(config->begin_keys()); | 234 for (DictionaryValue::key_iterator key(config->begin_keys()); |
| 241 key != config->end_keys(); ++key) { | 235 key != config->end_keys(); ++key) { |
| 242 std::string value; | 236 std::string value; |
| 243 if (!config->GetString(*key, &value)) { | 237 if (!config->GetString(*key, &value)) { |
| 244 LOG(ERROR) << *key << " is not a string."; | 238 LOG(ERROR) << *key << " is not a string."; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 261 } | 255 } |
| 262 } | 256 } |
| 263 | 257 |
| 264 bool DaemonControllerMac::DoShowPreferencePane(const std::string& config_data) { | 258 bool DaemonControllerMac::DoShowPreferencePane(const std::string& config_data) { |
| 265 if (!config_data.empty()) { | 259 if (!config_data.empty()) { |
| 266 FilePath config_path; | 260 FilePath config_path; |
| 267 if (!file_util::GetTempDir(&config_path)) { | 261 if (!file_util::GetTempDir(&config_path)) { |
| 268 LOG(ERROR) << "Failed to get filename for saving configuration data."; | 262 LOG(ERROR) << "Failed to get filename for saving configuration data."; |
| 269 return false; | 263 return false; |
| 270 } | 264 } |
| 271 config_path = config_path.Append(kServiceName ".json"); | 265 config_path = config_path.Append(kHostConfigFileName); |
| 272 | 266 |
| 273 int written = file_util::WriteFile(config_path, config_data.data(), | 267 int written = file_util::WriteFile(config_path, config_data.data(), |
| 274 config_data.size()); | 268 config_data.size()); |
| 275 if (written != static_cast<int>(config_data.size())) { | 269 if (written != static_cast<int>(config_data.size())) { |
| 276 LOG(ERROR) << "Failed to save configuration data to: " | 270 LOG(ERROR) << "Failed to save configuration data to: " |
| 277 << config_path.value(); | 271 << config_path.value(); |
| 278 return false; | 272 return false; |
| 279 } | 273 } |
| 280 } | 274 } |
| 281 | 275 |
| 282 FilePath pane_path; | 276 FilePath pane_path; |
| 283 // TODO(lambroslambrou): Use NSPreferencePanesDirectory once we start | 277 // TODO(lambroslambrou): Use NSPreferencePanesDirectory once we start |
| 284 // building against SDK 10.6. | 278 // building against SDK 10.6. |
| 285 if (!base::mac::GetLocalDirectory(NSLibraryDirectory, &pane_path)) { | 279 if (!base::mac::GetLocalDirectory(NSLibraryDirectory, &pane_path)) { |
| 286 LOG(ERROR) << "Failed to get directory for local preference panes."; | 280 LOG(ERROR) << "Failed to get directory for local preference panes."; |
| 287 return false; | 281 return false; |
| 288 } | 282 } |
| 289 pane_path = pane_path.Append("PreferencePanes") | 283 pane_path = pane_path.Append("PreferencePanes").Append(kPrefPaneFileName); |
| 290 .Append(kServiceName ".prefPane"); | |
| 291 | 284 |
| 292 FSRef pane_path_ref; | 285 FSRef pane_path_ref; |
| 293 if (!base::mac::FSRefFromPath(pane_path.value(), &pane_path_ref)) { | 286 if (!base::mac::FSRefFromPath(pane_path.value(), &pane_path_ref)) { |
| 294 LOG(ERROR) << "Failed to create FSRef"; | 287 LOG(ERROR) << "Failed to create FSRef"; |
| 295 return false; | 288 return false; |
| 296 } | 289 } |
| 297 OSStatus status = LSOpenFSRef(&pane_path_ref, NULL); | 290 OSStatus status = LSOpenFSRef(&pane_path_ref, NULL); |
| 298 if (status != noErr) { | 291 if (status != noErr) { |
| 299 OSSTATUS_LOG(ERROR, status) << "LSOpenFSRef failed for path: " | 292 OSSTATUS_LOG(ERROR, status) << "LSOpenFSRef failed for path: " |
| 300 << pane_path.value(); | 293 << pane_path.value(); |
| 301 return false; | 294 return false; |
| 302 } | 295 } |
| 303 | 296 |
| 304 CFNotificationCenterRef center = | 297 CFNotificationCenterRef center = |
| 305 CFNotificationCenterGetDistributedCenter(); | 298 CFNotificationCenterGetDistributedCenter(); |
| 306 CFNotificationCenterPostNotification(center, CFSTR(kServiceName), NULL, NULL, | 299 base::mac::ScopedCFTypeRef<CFStringRef> service_name( |
| 300 CFStringCreateWithCString(kCFAllocatorDefault, remoting::kServiceName, |
| 301 kCFStringEncodingUTF8)); |
| 302 CFNotificationCenterPostNotification(center, service_name, NULL, NULL, |
| 307 TRUE); | 303 TRUE); |
| 308 return true; | 304 return true; |
| 309 } | 305 } |
| 310 | 306 |
| 311 void DaemonControllerMac::DoStop(const CompletionCallback& done_callback) { | 307 void DaemonControllerMac::DoStop(const CompletionCallback& done_callback) { |
| 312 ShowPreferencePane("", done_callback); | 308 ShowPreferencePane("", done_callback); |
| 313 } | 309 } |
| 314 | 310 |
| 315 // CFNotificationCenterAddObserver ties the thread on which distributed | 311 // CFNotificationCenterAddObserver ties the thread on which distributed |
| 316 // notifications are received to the one on which it is first called. | 312 // notifications are received to the one on which it is first called. |
| 317 // This is safe because HostNPScriptObject::InvokeAsyncResultCallback | 313 // This is safe because HostNPScriptObject::InvokeAsyncResultCallback |
| 318 // bounces the invocation to the correct thread, so it doesn't matter | 314 // bounces the invocation to the correct thread, so it doesn't matter |
| 319 // which thread CompletionCallbacks are called on. | 315 // which thread CompletionCallbacks are called on. |
| 320 void DaemonControllerMac::RegisterForPreferencePaneNotifications( | 316 void DaemonControllerMac::RegisterForPreferencePaneNotifications( |
| 321 const CompletionCallback& done_callback) { | 317 const CompletionCallback& done_callback) { |
| 322 // We can only have one callback registered at a time. This is enforced by the | 318 // We can only have one callback registered at a time. This is enforced by the |
| 323 // UX flow of the web-app. | 319 // UX flow of the web-app. |
| 324 DCHECK(current_callback_.is_null()); | 320 DCHECK(current_callback_.is_null()); |
| 325 current_callback_ = done_callback; | 321 current_callback_ = done_callback; |
| 326 | 322 |
| 327 CFNotificationCenterAddObserver( | 323 CFNotificationCenterAddObserver( |
| 328 CFNotificationCenterGetDistributedCenter(), | 324 CFNotificationCenterGetDistributedCenter(), |
| 329 this, | 325 this, |
| 330 &DaemonControllerMac::PreferencePaneCallback, | 326 &DaemonControllerMac::PreferencePaneCallback, |
| 331 CFSTR(kUpdateSucceededNotificationName), | 327 CFSTR(UPDATE_SUCCEEDED_NOTIFICATION_NAME), |
| 332 NULL, | 328 NULL, |
| 333 CFNotificationSuspensionBehaviorDeliverImmediately); | 329 CFNotificationSuspensionBehaviorDeliverImmediately); |
| 334 CFNotificationCenterAddObserver( | 330 CFNotificationCenterAddObserver( |
| 335 CFNotificationCenterGetDistributedCenter(), | 331 CFNotificationCenterGetDistributedCenter(), |
| 336 this, | 332 this, |
| 337 &DaemonControllerMac::PreferencePaneCallback, | 333 &DaemonControllerMac::PreferencePaneCallback, |
| 338 CFSTR(kUpdateFailedNotificationName), | 334 CFSTR(UPDATE_FAILED_NOTIFICATION_NAME), |
| 339 NULL, | 335 NULL, |
| 340 CFNotificationSuspensionBehaviorDeliverImmediately); | 336 CFNotificationSuspensionBehaviorDeliverImmediately); |
| 341 } | 337 } |
| 342 | 338 |
| 343 void DaemonControllerMac::PreferencePaneCallbackDelegate(CFStringRef name) { | 339 void DaemonControllerMac::PreferencePaneCallbackDelegate(CFStringRef name) { |
| 344 AsyncResult result = RESULT_FAILED; | 340 AsyncResult result = RESULT_FAILED; |
| 345 if (CFStringCompare(name, CFSTR(kUpdateSucceededNotificationName), 0) == | 341 if (CFStringCompare(name, CFSTR(UPDATE_SUCCEEDED_NOTIFICATION_NAME), 0) == |
| 346 kCFCompareEqualTo) { | 342 kCFCompareEqualTo) { |
| 347 result = RESULT_OK; | 343 result = RESULT_OK; |
| 348 } else if (CFStringCompare(name, CFSTR(kUpdateFailedNotificationName), 0) == | 344 } else if (CFStringCompare(name, CFSTR(UPDATE_FAILED_NOTIFICATION_NAME), 0) == |
| 349 kCFCompareEqualTo) { | 345 kCFCompareEqualTo) { |
| 350 result = RESULT_FAILED; | 346 result = RESULT_FAILED; |
| 351 } else { | 347 } else { |
| 352 LOG(WARNING) << "Ignoring unexpected notification: " << name; | 348 LOG(WARNING) << "Ignoring unexpected notification: " << name; |
| 353 return; | 349 return; |
| 354 } | 350 } |
| 355 DCHECK(!current_callback_.is_null()); | 351 DCHECK(!current_callback_.is_null()); |
| 356 current_callback_.Run(result); | 352 current_callback_.Run(result); |
| 357 current_callback_.Reset(); | 353 current_callback_.Reset(); |
| 358 DeregisterForPreferencePaneNotifications(); | 354 DeregisterForPreferencePaneNotifications(); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 371 } | 367 } |
| 372 } | 368 } |
| 373 | 369 |
| 374 } // namespace | 370 } // namespace |
| 375 | 371 |
| 376 scoped_ptr<DaemonController> remoting::DaemonController::Create() { | 372 scoped_ptr<DaemonController> remoting::DaemonController::Create() { |
| 377 return scoped_ptr<DaemonController>(new DaemonControllerMac()); | 373 return scoped_ptr<DaemonController>(new DaemonControllerMac()); |
| 378 } | 374 } |
| 379 | 375 |
| 380 } // namespace remoting | 376 } // namespace remoting |
| OLD | NEW |