15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/api/messaging/native_message_process_host.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h" 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/prefs/pref_service.h" 114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/process/kill.h" 12ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "base/threading/sequenced_worker_pool.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h" 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/api/messaging/native_messaging_host_manifest.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/api/messaging/native_process_launcher.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_version_info.h" 175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "content/public/browser/browser_thread.h" 185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/pref_names.h" 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "extensions/common/constants.h" 203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "extensions/common/features/feature.h" 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/base/file_stream.h" 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/base/io_buffer.h" 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/base/net_errors.h" 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/base/net_util.h" 257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "url/gurl.h" 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Maximum message size in bytes for messages received from Native Messaging 302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// hosts. Message size is limited mainly to prevent Chrome from crashing when 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// native application misbehaves (e.g. starts writing garbage to the pipe). 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const size_t kMaximumMessageSize = 1024 * 1024; 332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Message header contains 4-byte integer size of the message. 352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const size_t kMessageHeaderSize = 4; 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Size of the buffer to be allocated for each read. 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const size_t kReadBufferSize = 4096; 392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kFailedToStartError[] = "Failed to start native messaging host."; 412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kInvalidNameError[] = 422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "Invalid native messaging host name specified."; 434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char kNativeHostExited[] = "Native host has exited."; 442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kNotFoundError[] = "Specified native messaging host not found."; 452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kForbiddenError[] = 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "Access to the specified native messaging host is forbidden."; 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kHostInputOuputError[] = 482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "Error when communicating with the native messaging host."; 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace extensions { 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// static 555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)NativeMessageProcessHost::PolicyPermission 565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)NativeMessageProcessHost::IsHostAllowed(const PrefService* pref_service, 575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const std::string& native_host_name) { 585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) NativeMessageProcessHost::PolicyPermission allow_result = ALLOW_ALL; 595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (pref_service->IsManagedPreference( 605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) pref_names::kNativeMessagingUserLevelHosts)) { 615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!pref_service->GetBoolean(pref_names::kNativeMessagingUserLevelHosts)) 625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) allow_result = ALLOW_SYSTEM_ONLY; 635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // All native messaging hosts are allowed if there is no blacklist. 665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!pref_service->IsManagedPreference(pref_names::kNativeMessagingBlacklist)) 675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return allow_result; 685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const base::ListValue* blacklist = 695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) pref_service->GetList(pref_names::kNativeMessagingBlacklist); 705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!blacklist) 715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return allow_result; 725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Check if the name or the wildcard is in the blacklist. 745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::StringValue name_value(native_host_name); 755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::StringValue wildcard_value("*"); 765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (blacklist->Find(name_value) == blacklist->end() && 775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) blacklist->Find(wildcard_value) == blacklist->end()) { 785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return allow_result; 795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // The native messaging host is blacklisted. Check the whitelist. 825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (pref_service->IsManagedPreference( 835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) pref_names::kNativeMessagingWhitelist)) { 845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const base::ListValue* whitelist = 855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) pref_service->GetList(pref_names::kNativeMessagingWhitelist); 865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (whitelist && whitelist->Find(name_value) != whitelist->end()) 875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return allow_result; 885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return DISALLOW; 915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NativeMessageProcessHost::NativeMessageProcessHost( 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::WeakPtr<Client> weak_client_ui, 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::string& source_extension_id, 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::string& native_host_name, 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int destination_port, 982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_ptr<NativeProcessLauncher> launcher) 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : weak_client_ui_(weak_client_ui), 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) source_extension_id_(source_extension_id), 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) native_host_name_(native_host_name), 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) destination_port_(destination_port), 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) launcher_(launcher.Pass()), 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) closed_(false), 1054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) process_handle_(base::kNullProcessHandle), 10623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#if defined(OS_POSIX) 107116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch read_file_(-1), 10823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#endif 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) read_pending_(false), 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) write_pending_(false) { 111effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // It's safe to use base::Unretained() here because NativeMessagePort always 1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // deletes us on the IO thread. 1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, 1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&NativeMessageProcessHost::LaunchHostProcess, 1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Unretained(this))); 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NativeMessageProcessHost::~NativeMessageProcessHost() { 121effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch DCHECK_CURRENTLY_ON(content::BrowserThread::IO); 1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Close(std::string()); 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_ptr<NativeMessageProcessHost> NativeMessageProcessHost::Create( 127ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch gfx::NativeView native_view, 1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::WeakPtr<Client> weak_client_ui, 1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::string& source_extension_id, 1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::string& native_host_name, 1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int destination_port, 1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) bool allow_user_level) { 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return CreateWithLauncher(weak_client_ui, source_extension_id, 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) native_host_name, destination_port, 1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) NativeProcessLauncher::CreateDefault( 1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) allow_user_level, native_view)); 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_ptr<NativeMessageProcessHost> 1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)NativeMessageProcessHost::CreateWithLauncher( 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::WeakPtr<Client> weak_client_ui, 1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::string& source_extension_id, 1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::string& native_host_name, 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int destination_port, 1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_ptr<NativeProcessLauncher> launcher) { 147effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_ptr<NativeMessageProcessHost> process(new NativeMessageProcessHost( 1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) weak_client_ui, source_extension_id, native_host_name, 1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) destination_port, launcher.Pass())); 1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return process.Pass(); 1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeMessageProcessHost::LaunchHostProcess() { 157effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch DCHECK_CURRENTLY_ON(content::BrowserThread::IO); 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GURL origin(std::string(kExtensionScheme) + "://" + source_extension_id_); 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) launcher_->Launch(origin, native_host_name_, 1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&NativeMessageProcessHost::OnHostProcessLaunched, 1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Unretained(this))); 1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeMessageProcessHost::OnHostProcessLaunched( 1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NativeProcessLauncher::LaunchResult result, 1674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::ProcessHandle process_handle, 16823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) base::File read_file, 16923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) base::File write_file) { 170effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch DCHECK_CURRENTLY_ON(content::BrowserThread::IO); 1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) switch (result) { 1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case NativeProcessLauncher::RESULT_INVALID_NAME: 1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Close(kInvalidNameError); 1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case NativeProcessLauncher::RESULT_NOT_FOUND: 1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Close(kNotFoundError); 1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case NativeProcessLauncher::RESULT_FORBIDDEN: 1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Close(kForbiddenError); 1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case NativeProcessLauncher::RESULT_FAILED_TO_START: 1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Close(kFailedToStartError); 1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case NativeProcessLauncher::RESULT_SUCCESS: 1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) process_handle_ = process_handle; 19023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#if defined(OS_POSIX) 19123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) // This object is not the owner of the file so it should not keep an fd. 19223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) read_file_ = read_file.GetPlatformFile(); 19323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#endif 194ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 195ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch scoped_refptr<base::TaskRunner> task_runner( 196ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch content::BrowserThread::GetBlockingPool()-> 197ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch GetTaskRunnerWithShutdownBehavior( 198ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)); 199ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 200010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) read_stream_.reset(new net::FileStream(read_file.Pass(), task_runner)); 201010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) write_stream_.reset(new net::FileStream(write_file.Pass(), task_runner)); 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) WaitRead(); 2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DoWrite(); 2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeMessageProcessHost::Send(const std::string& json) { 208effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch DCHECK_CURRENTLY_ON(content::BrowserThread::IO); 2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (closed_) 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Allocate new buffer for the message. 2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_refptr<net::IOBufferWithSize> buffer = 2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) new net::IOBufferWithSize(json.size() + kMessageHeaderSize); 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Copy size and content of the message to the buffer. 2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) COMPILE_ASSERT(sizeof(uint32) == kMessageHeaderSize, incorrect_header_size); 2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *reinterpret_cast<uint32*>(buffer->data()) = json.size(); 2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) memcpy(buffer->data() + kMessageHeaderSize, json.data(), json.size()); 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Push new message to the write queue. 2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) write_queue_.push(buffer); 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Send() may be called before the host process is started. In that case the 2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // message will be written when OnHostProcessLaunched() is called. If it's 2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // already started then write the message now. 2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (write_stream_) 2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DoWrite(); 2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(OS_POSIX) 2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeMessageProcessHost::OnFileCanReadWithoutBlocking(int fd) { 2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK_EQ(fd, read_file_); 2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DoRead(); 2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeMessageProcessHost::OnFileCanWriteWithoutBlocking(int fd) { 2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NOTREACHED(); 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif // !defined(OS_POSIX) 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeMessageProcessHost::ReadNowForTesting() { 2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DoRead(); 2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeMessageProcessHost::WaitRead() { 2484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (closed_) 2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(!read_pending_); 2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // On POSIX FileStream::Read() uses blocking thread pool, so it's better to 2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // wait for the file to become readable before calling DoRead(). Otherwise it 2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // would always be consuming one thread in the thread pool. On Windows 2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // FileStream uses overlapped IO, so that optimization isn't necessary there. 2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(OS_POSIX) 25890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) base::MessageLoopForIO::current()->WatchFileDescriptor( 25923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) read_file_, false /* persistent */, 26023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) base::MessageLoopForIO::WATCH_READ, &read_watcher_, this); 2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#else // defined(OS_POSIX) 2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DoRead(); 2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif // defined(!OS_POSIX) 2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeMessageProcessHost::DoRead() { 267effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch DCHECK_CURRENTLY_ON(content::BrowserThread::IO); 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) while (!closed_ && !read_pending_) { 2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) read_buffer_ = new net::IOBuffer(kReadBufferSize); 2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int result = read_stream_->Read( 272868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) read_buffer_.get(), 273868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) kReadBufferSize, 274868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::Bind(&NativeMessageProcessHost::OnRead, base::Unretained(this))); 2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) HandleReadResult(result); 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeMessageProcessHost::OnRead(int result) { 280effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch DCHECK_CURRENTLY_ON(content::BrowserThread::IO); 2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(read_pending_); 2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) read_pending_ = false; 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) HandleReadResult(result); 2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) WaitRead(); 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeMessageProcessHost::HandleReadResult(int result) { 289effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch DCHECK_CURRENTLY_ON(content::BrowserThread::IO); 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (closed_) 2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (result > 0) { 2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ProcessIncomingData(read_buffer_->data(), result); 2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (result == net::ERR_IO_PENDING) { 2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) read_pending_ = true; 2984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } else if (result == 0 || result == net::ERR_CONNECTION_RESET) { 2994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // On Windows we get net::ERR_CONNECTION_RESET for a broken pipe, while on 3004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // Posix read() returns 0 in that case. 3014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) Close(kNativeHostExited); 3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LOG(ERROR) << "Error when reading from Native Messaging host: " << result; 3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Close(kHostInputOuputError); 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeMessageProcessHost::ProcessIncomingData( 3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const char* data, int data_size) { 310effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch DCHECK_CURRENTLY_ON(content::BrowserThread::IO); 3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) incoming_data_.append(data, data_size); 3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) while (true) { 3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (incoming_data_.size() < kMessageHeaderSize) 3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) size_t message_size = 3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *reinterpret_cast<const uint32*>(incoming_data_.data()); 3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (message_size > kMaximumMessageSize) { 3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LOG(ERROR) << "Native Messaging host tried sending a message that is " 3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) << message_size << " bytes long."; 3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Close(kHostInputOuputError); 3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (incoming_data_.size() < message_size + kMessageHeaderSize) 3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, 3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&Client::PostMessageFromNativeProcess, weak_client_ui_, 3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) destination_port_, 334eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch incoming_data_.substr(kMessageHeaderSize, message_size))); 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) incoming_data_.erase(0, kMessageHeaderSize + message_size); 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeMessageProcessHost::DoWrite() { 341effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch DCHECK_CURRENTLY_ON(content::BrowserThread::IO); 3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) while (!write_pending_ && !closed_) { 344868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!current_write_buffer_.get() || 345868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) !current_write_buffer_->BytesRemaining()) { 3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (write_queue_.empty()) 3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) current_write_buffer_ = new net::DrainableIOBuffer( 349868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) write_queue_.front().get(), write_queue_.front()->size()); 3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) write_queue_.pop(); 3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 353868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) int result = 354868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) write_stream_->Write(current_write_buffer_.get(), 355868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) current_write_buffer_->BytesRemaining(), 356868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::Bind(&NativeMessageProcessHost::OnWritten, 357868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::Unretained(this))); 3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) HandleWriteResult(result); 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeMessageProcessHost::HandleWriteResult(int result) { 363effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch DCHECK_CURRENTLY_ON(content::BrowserThread::IO); 3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (result <= 0) { 3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (result == net::ERR_IO_PENDING) { 3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) write_pending_ = true; 3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LOG(ERROR) << "Error when writing to Native Messaging host: " << result; 3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Close(kHostInputOuputError); 3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) current_write_buffer_->DidConsume(result); 3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeMessageProcessHost::OnWritten(int result) { 379effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch DCHECK_CURRENTLY_ON(content::BrowserThread::IO); 3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(write_pending_); 3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) write_pending_ = false; 3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) HandleWriteResult(result); 3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DoWrite(); 3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeMessageProcessHost::Close(const std::string& error_message) { 389effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch DCHECK_CURRENTLY_ON(content::BrowserThread::IO); 3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!closed_) { 3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) closed_ = true; 3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) read_stream_.reset(); 3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) write_stream_.reset(); 3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, 3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&Client::CloseChannel, weak_client_ui_, 3972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) destination_port_, error_message)); 3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 4004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (process_handle_ != base::kNullProcessHandle) { 4014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // Kill the host process if necessary to make sure we don't leave zombies. 4024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // On OSX base::EnsureProcessTerminated() may block, so we have to post a 4034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // task on the blocking pool. 4044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#if defined(OS_MACOSX) 4054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) content::BrowserThread::PostBlockingPoolTask( 4064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) FROM_HERE, base::Bind(&base::EnsureProcessTerminated, process_handle_)); 4074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#else 4084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::EnsureProcessTerminated(process_handle_); 4094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#endif 4104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) process_handle_ = base::kNullProcessHandle; 4114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace extensions 415