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

Side by Side Diff: remoting/host/me2me_preference_pane.mm

Issue 10383204: Build pref-pane as universal binary on Mac OS X (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 7 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | remoting/remoting.gyp » ('j') | remoting/remoting.gyp » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 #import "remoting/host/me2me_preference_pane.h" 5 #import "remoting/host/me2me_preference_pane.h"
6 6
7 #import <Cocoa/Cocoa.h> 7 #import <Cocoa/Cocoa.h>
8 #include <CommonCrypto/CommonHMAC.h> 8 #include <CommonCrypto/CommonHMAC.h>
9 #include <errno.h>
9 #include <launch.h> 10 #include <launch.h>
10 #import <PreferencePanes/PreferencePanes.h> 11 #import <PreferencePanes/PreferencePanes.h>
11 #import <SecurityInterface/SFAuthorizationView.h> 12 #import <SecurityInterface/SFAuthorizationView.h>
13 #include <stdlib.h>
12 #include <unistd.h> 14 #include <unistd.h>
13 15
14 #include <fstream> 16 #include <fstream>
15 17
16 #include "base/eintr_wrapper.h" 18 #include "base/eintr_wrapper.h"
17 #include "base/logging.h"
18 #include "base/mac/authorization_util.h"
19 #include "base/mac/foundation_util.h"
20 #include "base/mac/launchd.h"
21 #include "base/mac/mac_logging.h"
22 #include "base/mac/scoped_launch_data.h" 19 #include "base/mac/scoped_launch_data.h"
23 #include "base/memory/scoped_ptr.h" 20 #include "base/memory/scoped_ptr.h"
24 #include "base/stringprintf.h"
25 #include "base/sys_string_conversions.h"
26 #include "remoting/host/host_config.h" 21 #include "remoting/host/host_config.h"
27 #include "third_party/jsoncpp/source/include/json/reader.h" 22 #include "third_party/jsoncpp/source/include/json/reader.h"
28 #include "third_party/jsoncpp/source/include/json/writer.h" 23 #include "third_party/jsoncpp/source/include/json/writer.h"
29 #include "third_party/modp_b64/modp_b64.h" 24 #include "third_party/modp_b64/modp_b64.h"
30 25
31 namespace { 26 namespace {
32 // The name of the Remoting Host service that is registered with launchd. 27 // The name of the Remoting Host service that is registered with launchd.
33 #define kServiceName "org.chromium.chromoting" 28 #define kServiceName "org.chromium.chromoting"
34 29
35 // Use separate named notifications for success and failure because sandboxed 30 // Use separate named notifications for success and failure because sandboxed
(...skipping 30 matching lines...) Expand all
66 const std::string& host_secret_hash) { 61 const std::string& host_secret_hash) {
67 // TODO(lambroslambrou): Once the "base" target supports building for 64-bit 62 // TODO(lambroslambrou): Once the "base" target supports building for 64-bit
68 // on Mac OS X, remove this code and replace it with |VerifyHostPinHash()| 63 // on Mac OS X, remove this code and replace it with |VerifyHostPinHash()|
69 // from host/pin_hash.h. 64 // from host/pin_hash.h.
70 size_t separator = host_secret_hash.find(':'); 65 size_t separator = host_secret_hash.find(':');
71 if (separator == std::string::npos) 66 if (separator == std::string::npos)
72 return false; 67 return false;
73 68
74 std::string method = host_secret_hash.substr(0, separator); 69 std::string method = host_secret_hash.substr(0, separator);
75 if (method != "hmac") { 70 if (method != "hmac") {
76 LOG(ERROR) << "Authentication method '" << method << "' not supported"; 71 NSLog(@"Authentication method '%s' not supported", method.c_str());
77 return false; 72 return false;
78 } 73 }
79 74
80 std::string hash_base64 = host_secret_hash.substr(separator + 1); 75 std::string hash_base64 = host_secret_hash.substr(separator + 1);
81 76
82 // Convert |hash_base64| to |hash|, based on code from base/base64.cc. 77 // Convert |hash_base64| to |hash|, based on code from base/base64.cc.
83 int hash_base64_size = static_cast<int>(hash_base64.size()); 78 int hash_base64_size = static_cast<int>(hash_base64.size());
84 std::string hash; 79 std::string hash;
85 hash.resize(modp_b64_decode_len(hash_base64_size)); 80 hash.resize(modp_b64_decode_len(hash_base64_size));
86 int hash_size = modp_b64_decode(&(hash[0]), hash_base64.data(), 81 int hash_size = modp_b64_decode(&(hash[0]), hash_base64.data(),
87 hash_base64_size); 82 hash_base64_size);
88 if (hash_size < 0) { 83 if (hash_size < 0) {
89 LOG(ERROR) << "Failed to parse host_secret_hash"; 84 NSLog(@"Failed to parse host_secret_hash");
90 return false; 85 return false;
91 } 86 }
92 hash.resize(hash_size); 87 hash.resize(hash_size);
93 88
94 std::string computed_hash; 89 std::string computed_hash;
95 computed_hash.resize(CC_SHA256_DIGEST_LENGTH); 90 computed_hash.resize(CC_SHA256_DIGEST_LENGTH);
96 91
97 CCHmac(kCCHmacAlgSHA256, 92 CCHmac(kCCHmacAlgSHA256,
98 host_id.data(), host_id.size(), 93 host_id.data(), host_id.size(),
99 pin.data(), pin.size(), 94 pin.data(), pin.size(),
100 &(computed_hash[0])); 95 &(computed_hash[0]));
101 96
102 return computed_hash == hash; 97 return computed_hash == hash;
103 } 98 }
104 99
105 } // namespace 100 } // namespace
106 101
102 // These methods are copied from base/mac, but with the logging changed to use
103 // NSLog().
104 //
105 // TODO(lambroslambrou): Once the "base" target supports building for 64-bit
106 // on Mac OS X, remove these implementations and use the ones in base/mac.
107 namespace base {
108 namespace mac {
109
110 // MessageForJob sends a single message to launchd with a simple dictionary
111 // mapping |operation| to |job_label|, and returns the result of calling
112 // launch_msg to send that message. On failure, returns NULL. The caller
113 // assumes ownership of the returned launch_data_t object.
114 launch_data_t MessageForJob(const std::string& job_label,
115 const char* operation) {
116 // launch_data_alloc returns something that needs to be freed.
117 ScopedLaunchData message(launch_data_alloc(LAUNCH_DATA_DICTIONARY));
118 if (!message) {
119 NSLog(@"launch_data_alloc");
120 return NULL;
121 }
122
123 // launch_data_new_string returns something that needs to be freed, but
124 // the dictionary will assume ownership when launch_data_dict_insert is
125 // called, so put it in a scoper and .release() it when given to the
126 // dictionary.
127 ScopedLaunchData job_label_launchd(launch_data_new_string(job_label.c_str()));
128 if (!job_label_launchd) {
129 NSLog(@"launch_data_new_string");
130 return NULL;
131 }
132
133 if (!launch_data_dict_insert(message,
134 job_label_launchd.release(),
135 operation)) {
136 return NULL;
137 }
138
139 return launch_msg(message);
140 }
141
142 pid_t PIDForJob(const std::string& job_label) {
Robert Sesek 2012/05/16 14:34:04 http://code.google.com/codesearch#OAMlx_jo-ck/src/
Robert Sesek 2012/05/16 14:37:43 Sorry, just saw your comment. Got confused by seei
Lambros 2012/05/16 17:43:44 mark@ told me it works, but it's currently unteste
143 ScopedLaunchData response(MessageForJob(job_label, LAUNCH_KEY_GETJOB));
144 if (!response) {
145 return -1;
146 }
147
148 launch_data_type_t response_type = launch_data_get_type(response);
149 if (response_type != LAUNCH_DATA_DICTIONARY) {
150 if (response_type == LAUNCH_DATA_ERRNO) {
151 NSLog(@"PIDForJob: error %d", launch_data_get_errno(response));
152 } else {
153 NSLog(@"PIDForJob: expected dictionary, got %d", response_type);
154 }
155 return -1;
156 }
157
158 launch_data_t pid_data = launch_data_dict_lookup(response,
159 LAUNCH_JOBKEY_PID);
160 if (!pid_data)
161 return 0;
162
163 if (launch_data_get_type(pid_data) != LAUNCH_DATA_INTEGER) {
164 NSLog(@"PIDForJob: expected integer");
165 return -1;
166 }
167
168 return launch_data_get_integer(pid_data);
169 }
170
171 OSStatus ExecuteWithPrivilegesAndGetPID(AuthorizationRef authorization,
172 const char* tool_path,
173 AuthorizationFlags options,
174 const char** arguments,
175 FILE** pipe,
176 pid_t* pid) {
177 // pipe may be NULL, but this function needs one. In that case, use a local
178 // pipe.
179 FILE* local_pipe;
180 FILE** pipe_pointer;
181 if (pipe) {
182 pipe_pointer = pipe;
183 } else {
184 pipe_pointer = &local_pipe;
185 }
186
187 // AuthorizationExecuteWithPrivileges wants |char* const*| for |arguments|,
188 // but it doesn't actually modify the arguments, and that type is kind of
189 // silly and callers probably aren't dealing with that. Put the cast here
190 // to make things a little easier on callers.
191 OSStatus status = AuthorizationExecuteWithPrivileges(authorization,
192 tool_path,
193 options,
194 (char* const*)arguments,
195 pipe_pointer);
196 if (status != errAuthorizationSuccess) {
197 return status;
198 }
199
200 long line_pid = -1;
201 size_t line_length = 0;
202 char* line_c = fgetln(*pipe_pointer, &line_length);
203 if (line_c) {
204 if (line_length > 0 && line_c[line_length - 1] == '\n') {
205 // line_c + line_length is the start of the next line if there is one.
206 // Back up one character.
207 --line_length;
208 }
209 std::string line(line_c, line_length);
210
211 // The version in base/mac used base::StringToInt() here.
212 line_pid = strtol(line.c_str(), NULL, 10);
213 if (line_pid == 0) {
214 NSLog(@"ExecuteWithPrivilegesAndGetPid: funny line: %s", line.c_str());
215 line_pid = -1;
216 }
217 } else {
218 NSLog(@"ExecuteWithPrivilegesAndGetPid: no line");
219 }
220
221 if (!pipe) {
222 fclose(*pipe_pointer);
223 }
224
225 if (pid) {
226 *pid = line_pid;
227 }
228
229 return status;
230 }
231
232 } // namespace mac
233 } // namespace base
234
107 namespace remoting { 235 namespace remoting {
108 JsonHostConfig::JsonHostConfig(const std::string& filename) 236 JsonHostConfig::JsonHostConfig(const std::string& filename)
109 : filename_(filename) { 237 : filename_(filename) {
110 } 238 }
111 239
112 JsonHostConfig::~JsonHostConfig() { 240 JsonHostConfig::~JsonHostConfig() {
113 } 241 }
114 242
115 bool JsonHostConfig::Read() { 243 bool JsonHostConfig::Read() {
116 std::ifstream file(filename_.c_str()); 244 std::ifstream file(filename_.c_str());
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
188 if (!have_new_config_) { 316 if (!have_new_config_) {
189 // It shouldn't be possible to hit the button if there is no config to 317 // It shouldn't be possible to hit the button if there is no config to
190 // apply, but check anyway just in case it happens somehow. 318 // apply, but check anyway just in case it happens somehow.
191 return; 319 return;
192 } 320 }
193 321
194 // Ensure the authorization token is up-to-date before using it. 322 // Ensure the authorization token is up-to-date before using it.
195 [self updateAuthorizationStatus]; 323 [self updateAuthorizationStatus];
196 [self updateUI]; 324 [self updateUI];
197 325
198 std::string pin = base::SysNSStringToUTF8([pin_ stringValue]); 326 std::string pin = [[pin_ stringValue] UTF8String];
199 std::string host_id, host_secret_hash; 327 std::string host_id, host_secret_hash;
200 bool result = (config_->GetString(remoting::kHostIdConfigPath, &host_id) && 328 bool result = (config_->GetString(remoting::kHostIdConfigPath, &host_id) &&
201 config_->GetString(remoting::kHostSecretHashConfigPath, 329 config_->GetString(remoting::kHostSecretHashConfigPath,
202 &host_secret_hash)); 330 &host_secret_hash));
203 DCHECK(result); 331 if (!result) {
Jamie 2012/05/16 20:31:34 In changing these DCHECKs, you're changing the Rel
332 [self showError];
333 return;
334 }
204 if (!IsPinValid(pin, host_id, host_secret_hash)) { 335 if (!IsPinValid(pin, host_id, host_secret_hash)) {
205 [self showIncorrectPinMessage]; 336 [self showIncorrectPinMessage];
206 return; 337 return;
207 } 338 }
208 339
209 [self applyNewServiceConfig]; 340 [self applyNewServiceConfig];
210 [self updateUI]; 341 [self updateUI];
211 } 342 }
212 343
213 - (void)onDisable:(id)sender { 344 - (void)onDisable:(id)sender {
214 // Ensure the authorization token is up-to-date before using it. 345 // Ensure the authorization token is up-to-date before using it.
215 [self updateAuthorizationStatus]; 346 [self updateAuthorizationStatus];
216 [self updateUI]; 347 [self updateUI];
217 if (!is_pane_unlocked_) 348 if (!is_pane_unlocked_)
218 return; 349 return;
219 350
220 if (![self runHelperAsRootWithCommand:"--disable" 351 if (![self runHelperAsRootWithCommand:"--disable"
221 inputData:""]) { 352 inputData:""]) {
222 LOG(ERROR) << "Failed to run the helper tool"; 353 NSLog(@"Failed to run the helper tool");
223 [self showError]; 354 [self showError];
224 return; 355 return;
225 } 356 }
226 357
227 // Stop the launchd job. This cannot easily be done by the helper tool, 358 // Stop the launchd job. This cannot easily be done by the helper tool,
228 // since the launchd job runs in the current user's context. 359 // since the launchd job runs in the current user's context.
229 [self sendJobControlMessage:LAUNCH_KEY_STOPJOB]; 360 [self sendJobControlMessage:LAUNCH_KEY_STOPJOB];
230 } 361 }
231 362
232 - (void)onNewConfigFile:(NSNotification*)notification { 363 - (void)onNewConfigFile:(NSNotification*)notification {
(...skipping 23 matching lines...) Expand all
256 is_service_running_ = (job_pid > 0); 387 is_service_running_ = (job_pid > 0);
257 } 388 }
258 389
259 - (void)updateAuthorizationStatus { 390 - (void)updateAuthorizationStatus {
260 is_pane_unlocked_ = [authorization_view_ updateStatus:authorization_view_]; 391 is_pane_unlocked_ = [authorization_view_ updateStatus:authorization_view_];
261 } 392 }
262 393
263 - (void)readNewConfig { 394 - (void)readNewConfig {
264 std::string file; 395 std::string file;
265 if (!GetTemporaryConfigFilePath(&file)) { 396 if (!GetTemporaryConfigFilePath(&file)) {
266 LOG(ERROR) << "Failed to get path of configuration data."; 397 NSLog(@"Failed to get path of configuration data.");
267 [self showError]; 398 [self showError];
268 return; 399 return;
269 } 400 }
270 if (access(file.c_str(), F_OK) != 0) 401 if (access(file.c_str(), F_OK) != 0)
271 return; 402 return;
272 403
273 scoped_ptr<remoting::JsonHostConfig> new_config_( 404 scoped_ptr<remoting::JsonHostConfig> new_config_(
274 new remoting::JsonHostConfig(file)); 405 new remoting::JsonHostConfig(file));
275 if (!new_config_->Read()) { 406 if (!new_config_->Read()) {
276 // Report the error, because the file exists but couldn't be read. The 407 // Report the error, because the file exists but couldn't be read. The
277 // case of non-existence is normal and expected. 408 // case of non-existence is normal and expected.
278 LOG(ERROR) << "Error reading configuration data from " << file.c_str(); 409 NSLog(@"Error reading configuration data from %s", file.c_str());
279 [self showError]; 410 [self showError];
280 return; 411 return;
281 } 412 }
282 remove(file.c_str()); 413 remove(file.c_str());
283 if (!IsConfigValid(new_config_.get())) { 414 if (!IsConfigValid(new_config_.get())) {
284 LOG(ERROR) << "Invalid configuration data read."; 415 NSLog(@"Invalid configuration data read.");
285 [self showError]; 416 [self showError];
286 return; 417 return;
287 } 418 }
288 419
289 config_.swap(new_config_); 420 config_.swap(new_config_);
290 have_new_config_ = YES; 421 have_new_config_ = YES;
291 } 422 }
292 423
293 - (void)updateUI { 424 - (void)updateUI {
294 // TODO(lambroslambrou): These strings should be localized. 425 // TODO(lambroslambrou): These strings should be localized.
295 #ifdef OFFICIAL_BUILD 426 #ifdef OFFICIAL_BUILD
296 NSString* name = @"Chrome Remote Desktop"; 427 NSString* name = @"Chrome Remote Desktop";
297 #else 428 #else
298 NSString* name = @"Chromoting"; 429 NSString* name = @"Chromoting";
299 #endif 430 #endif
300 NSString* message; 431 NSString* message;
301 if (is_service_running_) { 432 if (is_service_running_) {
302 message = [NSString stringWithFormat:@"%@ is enabled", name]; 433 message = [NSString stringWithFormat:@"%@ is enabled", name];
303 } else { 434 } else {
304 message = [NSString stringWithFormat:@"%@ is disabled", name]; 435 message = [NSString stringWithFormat:@"%@ is disabled", name];
305 } 436 }
306 [status_message_ setStringValue:message]; 437 [status_message_ setStringValue:message];
307 438
308 std::string email; 439 std::string email;
309 if (config_.get()) { 440 if (config_.get()) {
310 bool result = config_->GetString(remoting::kXmppLoginConfigPath, &email); 441 bool result = config_->GetString(remoting::kXmppLoginConfigPath, &email);
311 442
312 // The config has already been checked by |IsConfigValid|. 443 // The config has already been checked by |IsConfigValid|.
313 DCHECK(result); 444 if (!result) {
445 [self showError];
446 return;
447 }
314 } 448 }
315 [email_ setStringValue:base::SysUTF8ToNSString(email)]; 449 [email_ setStringValue:[NSString stringWithUTF8String:email.c_str()]];
316 450
317 [disable_button_ setEnabled:(is_pane_unlocked_ && is_service_running_)]; 451 [disable_button_ setEnabled:(is_pane_unlocked_ && is_service_running_)];
318 [pin_instruction_message_ setEnabled:have_new_config_]; 452 [pin_instruction_message_ setEnabled:have_new_config_];
319 [email_ setEnabled:have_new_config_]; 453 [email_ setEnabled:have_new_config_];
320 [pin_ setEnabled:have_new_config_]; 454 [pin_ setEnabled:have_new_config_];
321 [apply_button_ setEnabled:(is_pane_unlocked_ && have_new_config_)]; 455 [apply_button_ setEnabled:(is_pane_unlocked_ && have_new_config_)];
322 } 456 }
323 457
324 - (void)showError { 458 - (void)showError {
325 NSAlert* alert = [[NSAlert alloc] init]; 459 NSAlert* alert = [[NSAlert alloc] init];
(...skipping 17 matching lines...) Expand all
343 contextInfo:nil]; 477 contextInfo:nil];
344 [alert release]; 478 [alert release];
345 } 479 }
346 480
347 - (void)applyNewServiceConfig { 481 - (void)applyNewServiceConfig {
348 [self updateServiceStatus]; 482 [self updateServiceStatus];
349 std::string serialized_config = config_->GetSerializedData(); 483 std::string serialized_config = config_->GetSerializedData();
350 const char* command = is_service_running_ ? "--save-config" : "--enable"; 484 const char* command = is_service_running_ ? "--save-config" : "--enable";
351 if (![self runHelperAsRootWithCommand:command 485 if (![self runHelperAsRootWithCommand:command
352 inputData:serialized_config]) { 486 inputData:serialized_config]) {
353 LOG(ERROR) << "Failed to run the helper tool"; 487 NSLog(@"Failed to run the helper tool");
354 [self showError]; 488 [self showError];
355 return; 489 return;
356 } 490 }
357 491
358 have_new_config_ = NO; 492 have_new_config_ = NO;
359 493
360 // If the service is running, send a signal to cause it to reload its 494 // If the service is running, send a signal to cause it to reload its
361 // configuration, otherwise start the service. 495 // configuration, otherwise start the service.
362 if (is_service_running_) { 496 if (is_service_running_) {
363 pid_t job_pid = base::mac::PIDForJob(kServiceName); 497 pid_t job_pid = base::mac::PIDForJob(kServiceName);
364 if (job_pid > 0) { 498 if (job_pid > 0) {
365 kill(job_pid, SIGHUP); 499 kill(job_pid, SIGHUP);
366 } else { 500 } else {
367 LOG(ERROR) << "Failed to obtain PID of service " << kServiceName; 501 NSLog(@"Failed to obtain PID of service " kServiceName);
368 [self showError]; 502 [self showError];
369 } 503 }
370 } else { 504 } else {
371 [self sendJobControlMessage:LAUNCH_KEY_STARTJOB]; 505 [self sendJobControlMessage:LAUNCH_KEY_STARTJOB];
372 } 506 }
373 507
374 // Broadcast a distributed notification to inform the plugin that the 508 // Broadcast a distributed notification to inform the plugin that the
375 // configuration has been applied. 509 // configuration has been applied.
376 [self notifyPlugin: kUpdateSucceededNotificationName]; 510 [self notifyPlugin: kUpdateSucceededNotificationName];
377 } 511 }
378 512
379 - (BOOL)runHelperAsRootWithCommand:(const char*)command 513 - (BOOL)runHelperAsRootWithCommand:(const char*)command
380 inputData:(const std::string&)input_data { 514 inputData:(const std::string&)input_data {
381 AuthorizationRef authorization = 515 AuthorizationRef authorization =
382 [[authorization_view_ authorization] authorizationRef]; 516 [[authorization_view_ authorization] authorizationRef];
383 if (!authorization) { 517 if (!authorization) {
384 LOG(ERROR) << "Failed to obtain authorizationRef"; 518 NSLog(@"Failed to obtain authorizationRef");
385 return NO; 519 return NO;
386 } 520 }
387 521
388 // TODO(lambroslambrou): Replace the deprecated ExecuteWithPrivileges 522 // TODO(lambroslambrou): Replace the deprecated ExecuteWithPrivileges
389 // call with a launchd-based helper tool, which is more secure. 523 // call with a launchd-based helper tool, which is more secure.
390 // http://crbug.com/120903 524 // http://crbug.com/120903
391 const char* arguments[] = { command, NULL }; 525 const char* arguments[] = { command, NULL };
392 FILE* pipe = NULL; 526 FILE* pipe = NULL;
393 pid_t pid; 527 pid_t pid;
394 OSStatus status = base::mac::ExecuteWithPrivilegesAndGetPID( 528 OSStatus status = base::mac::ExecuteWithPrivilegesAndGetPID(
395 authorization, 529 authorization,
396 kHelperTool, 530 kHelperTool,
397 kAuthorizationFlagDefaults, 531 kAuthorizationFlagDefaults,
398 arguments, 532 arguments,
399 &pipe, 533 &pipe,
400 &pid); 534 &pid);
401 if (status != errAuthorizationSuccess) { 535 if (status != errAuthorizationSuccess) {
402 OSSTATUS_LOG(ERROR, status) << "AuthorizationExecuteWithPrivileges"; 536 NSLog(@"AuthorizationExecuteWithPrivileges: %s (%d)",
537 GetMacOSStatusErrorString(status), static_cast<int>(status));
403 return NO; 538 return NO;
404 } 539 }
405 if (pid == -1) { 540 if (pid == -1) {
406 LOG(ERROR) << "Failed to get child PID"; 541 NSLog(@"Failed to get child PID");
407 if (pipe) 542 if (pipe)
408 fclose(pipe); 543 fclose(pipe);
409 544
410 return NO; 545 return NO;
411 } 546 }
412 if (!pipe) { 547 if (!pipe) {
413 LOG(ERROR) << "Unexpected NULL pipe"; 548 NSLog(@"Unexpected NULL pipe");
414 return NO; 549 return NO;
415 } 550 }
416 551
417 // Some cleanup is needed (closing the pipe and waiting for the child 552 // Some cleanup is needed (closing the pipe and waiting for the child
418 // process), so flag any errors before returning. 553 // process), so flag any errors before returning.
419 BOOL error = NO; 554 BOOL error = NO;
420 555
421 if (!input_data.empty()) { 556 if (!input_data.empty()) {
422 size_t bytes_written = fwrite(input_data.data(), sizeof(char), 557 size_t bytes_written = fwrite(input_data.data(), sizeof(char),
423 input_data.size(), pipe); 558 input_data.size(), pipe);
424 // According to the fwrite manpage, a partial count is returned only if a 559 // According to the fwrite manpage, a partial count is returned only if a
425 // write error has occurred. 560 // write error has occurred.
426 if (bytes_written != input_data.size()) { 561 if (bytes_written != input_data.size()) {
427 LOG(ERROR) << "Failed to write data to child process"; 562 NSLog(@"Failed to write data to child process");
428 error = YES; 563 error = YES;
429 } 564 }
430 } 565 }
431 566
432 // In all cases, fclose() should be called with the returned FILE*. In the 567 // In all cases, fclose() should be called with the returned FILE*. In the
433 // case of sending data to the child, this needs to be done before calling 568 // case of sending data to the child, this needs to be done before calling
434 // waitpid(), since the child reads until EOF on its stdin, so calling 569 // waitpid(), since the child reads until EOF on its stdin, so calling
435 // waitpid() first would result in deadlock. 570 // waitpid() first would result in deadlock.
436 if (fclose(pipe) != 0) { 571 if (fclose(pipe) != 0) {
437 PLOG(ERROR) << "fclose"; 572 NSLog(@"fclose failed with error %d", errno);
438 error = YES; 573 error = YES;
439 } 574 }
440 575
441 int exit_status; 576 int exit_status;
442 pid_t wait_result = HANDLE_EINTR(waitpid(pid, &exit_status, 0)); 577 pid_t wait_result = HANDLE_EINTR(waitpid(pid, &exit_status, 0));
443 if (wait_result != pid) { 578 if (wait_result != pid) {
444 PLOG(ERROR) << "waitpid"; 579 NSLog(@"waitpid failed with error %d", errno);
445 error = YES; 580 error = YES;
446 } 581 }
447 582
448 // No more cleanup needed. 583 // No more cleanup needed.
449 if (error) 584 if (error)
450 return NO; 585 return NO;
451 586
452 if (WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == 0) { 587 if (WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == 0) {
453 return YES; 588 return YES;
454 } else { 589 } else {
455 LOG(ERROR) << kHelperTool << " failed with exit status " << exit_status; 590 NSLog(@"%s failed with exit status %d", kHelperTool, exit_status);
456 return NO; 591 return NO;
457 } 592 }
458 } 593 }
459 594
460 - (BOOL)sendJobControlMessage:(const char*)launch_key { 595 - (BOOL)sendJobControlMessage:(const char*)launch_key {
461 base::mac::ScopedLaunchData response( 596 base::mac::ScopedLaunchData response(
462 base::mac::MessageForJob(kServiceName, launch_key)); 597 base::mac::MessageForJob(kServiceName, launch_key));
463 if (!response) { 598 if (!response) {
464 LOG(ERROR) << "Failed to send message to launchd"; 599 NSLog(@"Failed to send message to launchd");
465 [self showError]; 600 [self showError];
466 return NO; 601 return NO;
467 } 602 }
468 603
469 // Expect a response of type LAUNCH_DATA_ERRNO. 604 // Expect a response of type LAUNCH_DATA_ERRNO.
470 launch_data_type_t type = launch_data_get_type(response.get()); 605 launch_data_type_t type = launch_data_get_type(response.get());
471 if (type != LAUNCH_DATA_ERRNO) { 606 if (type != LAUNCH_DATA_ERRNO) {
472 LOG(ERROR) << "launchd returned unexpected type: " << type; 607 NSLog(@"launchd returned unexpected type: %d", type);
473 [self showError]; 608 [self showError];
474 return NO; 609 return NO;
475 } 610 }
476 611
477 int error = launch_data_get_errno(response.get()); 612 int error = launch_data_get_errno(response.get());
478 if (error) { 613 if (error) {
479 LOG(ERROR) << "launchd returned error: " << error; 614 NSLog(@"launchd returned error: %d", error);
480 [self showError]; 615 [self showError];
481 return NO; 616 return NO;
482 } 617 }
483 return YES; 618 return YES;
484 } 619 }
485 620
486 - (void)notifyPlugin:(const char*)message { 621 - (void)notifyPlugin:(const char*)message {
487 NSDistributedNotificationCenter* center = 622 NSDistributedNotificationCenter* center =
488 [NSDistributedNotificationCenter defaultCenter]; 623 [NSDistributedNotificationCenter defaultCenter];
489 NSString* name = [NSString stringWithUTF8String:message]; 624 NSString* name = [NSString stringWithUTF8String:message];
490 [center postNotificationName:name 625 [center postNotificationName:name
491 object:nil 626 object:nil
492 userInfo:nil]; 627 userInfo:nil];
493 } 628 }
494 629
495 @end 630 @end
OLDNEW
« no previous file with comments | « no previous file | remoting/remoting.gyp » ('j') | remoting/remoting.gyp » ('J')

Powered by Google App Engine
This is Rietveld 408576698