blob: 1d0c89e3db162cdf9e59368efa8ff118e2823afd [file] [log] [blame]
Darin Petkov33af05c2012-02-28 10:10:30 +01001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "shill/vpn_service.h"
6
Darin Petkov02867712012-03-12 14:25:05 +01007#include <algorithm>
Darin Petkov33af05c2012-02-28 10:10:30 +01008
Darin Petkov02867712012-03-12 14:25:05 +01009#include <base/logging.h>
10#include <base/stringprintf.h>
11#include <chromeos/dbus/service_constants.h>
12
13#include "shill/key_value_store.h"
Paul Stewart65512e12012-03-26 18:01:08 -070014#include "shill/manager.h"
Darin Petkov5eb05422012-05-11 15:45:25 +020015#include "shill/scope_logger.h"
Darin Petkov33af05c2012-02-28 10:10:30 +010016#include "shill/technology.h"
17#include "shill/vpn_driver.h"
18
Darin Petkov5eb05422012-05-11 15:45:25 +020019using base::Bind;
Darin Petkov02867712012-03-12 14:25:05 +010020using base::StringPrintf;
Darin Petkov5eb05422012-05-11 15:45:25 +020021using base::Unretained;
Darin Petkov02867712012-03-12 14:25:05 +010022using std::replace_if;
Darin Petkov33af05c2012-02-28 10:10:30 +010023using std::string;
24
25namespace shill {
26
Darin Petkov79d74c92012-03-07 17:20:32 +010027VPNService::VPNService(ControlInterface *control,
Darin Petkov33af05c2012-02-28 10:10:30 +010028 EventDispatcher *dispatcher,
29 Metrics *metrics,
30 Manager *manager,
31 VPNDriver *driver)
Darin Petkov79d74c92012-03-07 17:20:32 +010032 : Service(control, dispatcher, metrics, manager, Technology::kVPN),
Paul Stewart22807992012-04-11 08:48:31 -070033 driver_(driver) {
Darin Petkov2f903b32012-04-18 12:56:43 +020034 set_connectable(true);
Darin Petkovcb715292012-04-25 13:04:37 +020035 set_save_credentials(false);
Paul Stewart22807992012-04-11 08:48:31 -070036 mutable_store()->RegisterString(flimflam::kVPNDomainProperty, &vpn_domain_);
37}
Darin Petkov33af05c2012-02-28 10:10:30 +010038
39VPNService::~VPNService() {}
40
Darin Petkov2f903b32012-04-18 12:56:43 +020041bool VPNService::TechnologyIs(const Technology::Identifier type) const {
42 return type == Technology::kVPN;
43}
44
Darin Petkov33af05c2012-02-28 10:10:30 +010045void VPNService::Connect(Error *error) {
Darin Petkov5eb05422012-05-11 15:45:25 +020046 SLOG(VPN, 2) << __func__ << " @ " << friendly_name();
Darin Petkov2f903b32012-04-18 12:56:43 +020047 if (IsConnected() || IsConnecting()) {
48 Error::PopulateAndLog(
49 error, Error::kAlreadyConnected, "VPN service already connected.");
50 return;
51 }
Darin Petkov6aa21872012-03-09 16:10:19 +010052 Service::Connect(error);
Darin Petkov79d74c92012-03-07 17:20:32 +010053 driver_->Connect(this, error);
Darin Petkov33af05c2012-02-28 10:10:30 +010054}
55
Darin Petkov6aa21872012-03-09 16:10:19 +010056void VPNService::Disconnect(Error *error) {
Darin Petkov5eb05422012-05-11 15:45:25 +020057 SLOG(VPN, 2) << __func__ << " @ " << friendly_name();
Darin Petkov6aa21872012-03-09 16:10:19 +010058 Service::Disconnect(error);
59 driver_->Disconnect();
60}
61
Darin Petkov33af05c2012-02-28 10:10:30 +010062string VPNService::GetStorageIdentifier() const {
Darin Petkov02867712012-03-12 14:25:05 +010063 return storage_id_;
64}
65
66// static
67string VPNService::CreateStorageIdentifier(const KeyValueStore &args,
68 Error *error) {
Darin Petkov7f060332012-03-14 11:46:47 +010069 string host = args.LookupString(flimflam::kProviderHostProperty, "");
Darin Petkov02867712012-03-12 14:25:05 +010070 if (host.empty()) {
71 Error::PopulateAndLog(
72 error, Error::kInvalidProperty, "Missing VPN host.");
73 return "";
74 }
Darin Petkov7f060332012-03-14 11:46:47 +010075 string name = args.LookupString(flimflam::kProviderNameProperty, "");
Darin Petkov02867712012-03-12 14:25:05 +010076 if (name.empty()) {
Paul Stewart451aa7f2012-04-11 19:07:58 -070077 name = args.LookupString(flimflam::kNameProperty, "");
78 if (name.empty()) {
79 Error::PopulateAndLog(
80 error, Error::kNotSupported, "Missing VPN name.");
81 return "";
82 }
Darin Petkov02867712012-03-12 14:25:05 +010083 }
84 string id = StringPrintf("vpn_%s_%s", host.c_str(), name.c_str());
85 replace_if(id.begin(), id.end(), &Service::IllegalChar, '_');
86 return id;
Darin Petkov33af05c2012-02-28 10:10:30 +010087}
88
89string VPNService::GetDeviceRpcId(Error *error) {
Darin Petkov33af05c2012-02-28 10:10:30 +010090 error->Populate(Error::kNotSupported);
91 return "/";
92}
93
Darin Petkovf3c71d72012-03-21 12:32:15 +010094bool VPNService::Load(StoreInterface *storage) {
95 return Service::Load(storage) &&
96 driver_->Load(storage, GetStorageIdentifier());
97}
98
99bool VPNService::Save(StoreInterface *storage) {
100 return Service::Save(storage) &&
Darin Petkovcb715292012-04-25 13:04:37 +0200101 driver_->Save(storage, GetStorageIdentifier(), save_credentials());
Darin Petkovf3c71d72012-03-21 12:32:15 +0100102}
103
Paul Stewart65512e12012-03-26 18:01:08 -0700104bool VPNService::Unload() {
Darin Petkova0e645e2012-04-25 11:38:59 +0200105 // The base method also disconnects the service.
Paul Stewart65512e12012-03-26 18:01:08 -0700106 Service::Unload();
107
Darin Petkovcb715292012-04-25 13:04:37 +0200108 set_save_credentials(false);
109 driver_->UnloadCredentials();
110
Paul Stewart65512e12012-03-26 18:01:08 -0700111 // Ask the VPN provider to remove us from its list.
112 manager()->vpn_provider()->RemoveService(this);
113
114 return true;
115}
116
Paul Stewartebd38562012-03-23 13:06:40 -0700117void VPNService::InitDriverPropertyStore() {
118 driver_->InitPropertyStore(mutable_store());
119}
120
Darin Petkov1d0080a2012-04-30 17:10:36 +0200121void VPNService::MakeFavorite() {
122 // The base MakeFavorite method also sets auto_connect_ to true
123 // which is not desirable for VPN services.
124 set_favorite(true);
125}
126
Darin Petkov5eb05422012-05-11 15:45:25 +0200127void VPNService::SetConnection(const ConnectionRefPtr &connection) {
128 // Construct the connection binder here rather than in the constructor because
129 // this service's |friendly_name_| (which will be used for binder logging) may
130 // be initialized late. Also, there's really no reason to construct a binder
131 // if we never connect to this service. It's safe to use an unretained
132 // callback to driver's method because both the binder and the driver will be
133 // destroyed when this service is destructed.
134 if (!connection_binder_.get()) {
135 connection_binder_.reset(
136 new Connection::Binder(friendly_name(),
137 Bind(&VPNDriver::OnConnectionDisconnected,
138 Unretained(driver_.get()))));
139 }
140 // Note that |connection_| is a reference-counted pointer and is always set
141 // through this method. This means that the connection binder will not be
142 // notified when the connection is destructed (because we will unbind it first
143 // here when it's set to NULL, or because the binder will already be destroyed
144 // by ~VPNService) -- it will be notified only if the connection disconnects
145 // (e.g., because an underlying connection is destructed).
146 connection_binder_->Attach(connection);
147 Service::SetConnection(connection);
148}
149
Darin Petkov33af05c2012-02-28 10:10:30 +0100150} // namespace shill