// Copyright 2015 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "extensions/browser/api/socket/app_firewall_hole_manager.h" #include #include "base/bind.h" #include "base/stl_util.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" #include "content/public/browser/browser_context.h" #include "extensions/browser/app_window/app_window.h" using chromeos::FirewallHole; using content::BrowserContext; namespace extensions { namespace { class AppFirewallHoleManagerFactory : public BrowserContextKeyedServiceFactory { public: static AppFirewallHoleManager* GetForBrowserContext(BrowserContext* context, bool create) { return static_cast( GetInstance()->GetServiceForBrowserContext(context, create)); } static AppFirewallHoleManagerFactory* GetInstance() { return Singleton::get(); } AppFirewallHoleManagerFactory() : BrowserContextKeyedServiceFactory( "AppFirewallHoleManager", BrowserContextDependencyManager::GetInstance()) { DependsOn(AppWindowRegistry::Factory::GetInstance()); } ~AppFirewallHoleManagerFactory() override {} private: // BrowserContextKeyedServiceFactory KeyedService* BuildServiceInstanceFor( BrowserContext* context) const override { return new AppFirewallHoleManager(context); } BrowserContext* GetBrowserContextToUse( BrowserContext* context) const override { return context; } }; bool HasVisibleAppWindows(BrowserContext* context, const std::string& extension_id) { AppWindowRegistry* registry = AppWindowRegistry::Get(context); for (const AppWindow* window : registry->GetAppWindowsForApp(extension_id)) { if (!window->is_hidden()) { return true; } } return false; } } // namespace AppFirewallHole::~AppFirewallHole() { manager_->Close(this); } AppFirewallHole::AppFirewallHole(AppFirewallHoleManager* manager, PortType type, uint16_t port, const std::string& extension_id) : type_(type), port_(port), extension_id_(extension_id), manager_(manager), weak_factory_(this) { } void AppFirewallHole::SetVisible(bool app_visible) { app_visible_ = app_visible; if (app_visible_) { if (!firewall_hole_) { FirewallHole::Open(type_, port_, "" /* all interfaces */, base::Bind(&AppFirewallHole::OnFirewallHoleOpened, weak_factory_.GetWeakPtr())); } } else { firewall_hole_.reset(nullptr); } } void AppFirewallHole::OnFirewallHoleOpened( scoped_ptr firewall_hole) { if (app_visible_) { DCHECK(!firewall_hole_); firewall_hole_ = firewall_hole.Pass(); } } AppFirewallHoleManager::AppFirewallHoleManager(BrowserContext* context) : context_(context), observer_(this) { observer_.Add(AppWindowRegistry::Get(context)); } AppFirewallHoleManager::~AppFirewallHoleManager() { STLDeleteValues(&tracked_holes_); } AppFirewallHoleManager* AppFirewallHoleManager::Get(BrowserContext* context) { return AppFirewallHoleManagerFactory::GetForBrowserContext(context, true); } scoped_ptr AppFirewallHoleManager::Open( AppFirewallHole::PortType type, uint16_t port, const std::string& extension_id) { scoped_ptr hole( new AppFirewallHole(this, type, port, extension_id)); tracked_holes_.insert(std::make_pair(extension_id, hole.get())); if (HasVisibleAppWindows(context_, extension_id)) { hole->SetVisible(true); } return hole.Pass(); } void AppFirewallHoleManager::Close(AppFirewallHole* hole) { auto range = tracked_holes_.equal_range(hole->extension_id()); for (auto iter = range.first; iter != range.second; ++iter) { if (iter->second == hole) { tracked_holes_.erase(iter); return; } } NOTREACHED(); } void AppFirewallHoleManager::OnAppWindowRemoved(AppWindow* app_window) { OnAppWindowHidden(app_window); } void AppFirewallHoleManager::OnAppWindowHidden(AppWindow* app_window) { DCHECK(context_ == app_window->browser_context()); if (!HasVisibleAppWindows(context_, app_window->extension_id())) { const auto& range = tracked_holes_.equal_range(app_window->extension_id()); for (auto iter = range.first; iter != range.second; ++iter) { iter->second->SetVisible(false); } } } void AppFirewallHoleManager::OnAppWindowShown(AppWindow* app_window, bool was_hidden) { const auto& range = tracked_holes_.equal_range(app_window->extension_id()); for (auto iter = range.first; iter != range.second; ++iter) { iter->second->SetVisible(true); } } } // namespace extensions