shill: Setup .Task RPC service for incoming VPN communication.

This will be used by OpenVPN, for example, to communicate back to shill
connection information (IP, DNS, etc.).

The RPC class model mostly follows the existing RPC adaptor classes (Manager,
Service, etc.).

Task is a bit overloaded and confusing in the context of shill so calling the
RPC object RPCTask instead. Also, the current intent is for this object to just
handle RPC service calls. Once the initial VPN implementation is in we may
decide to rename and refactor these objects.

BUG=chromium-os:26993
TEST=unit test

Change-Id: Ie294524b954c4a589c07ad285c7703cbbf9157d6
Reviewed-on: https://gerrit.chromium.org/gerrit/17047
Reviewed-by: Darin Petkov <petkov@chromium.org>
Tested-by: Darin Petkov <petkov@chromium.org>
Reviewed-by: Sam Leffler <sleffler@chromium.org>
Commit-Ready: Darin Petkov <petkov@chromium.org>
diff --git a/Makefile b/Makefile
index 4fdece1..30ce77a 100644
--- a/Makefile
+++ b/Makefile
@@ -64,7 +64,8 @@
 	org.chromium.flimflam.IPConfig>flimflam-ipconfig \
 	org.chromium.flimflam.Manager>flimflam-manager \
 	org.chromium.flimflam.Profile>flimflam-profile \
-	org.chromium.flimflam.Service>flimflam-service
+	org.chromium.flimflam.Service>flimflam-service \
+	org.chromium.flimflam.Task>flimflam-task
 
 define ADD_BINDING
 $(eval _SOURCE = $(word 1,$(subst >, ,$(1))))
@@ -173,6 +174,8 @@
 	supplicant_bss_proxy.o \
 	supplicant_interface_proxy.o \
 	supplicant_process_proxy.o \
+	rpc_task.o \
+	rpc_task_dbus_adaptor.o \
 	technology.o \
 	vpn_provider.o \
 	vpn_service.o \
@@ -273,6 +276,7 @@
 	property_store_unittest.o \
 	resolver_unittest.o \
 	routing_table_unittest.o \
+	rpc_task_unittest.o \
 	rtnl_handler_unittest.o \
 	rtnl_listener_unittest.o \
 	rtnl_message_unittest.o \
diff --git a/adaptor_interfaces.h b/adaptor_interfaces.h
index 605050c..f0a24ee 100644
--- a/adaptor_interfaces.h
+++ b/adaptor_interfaces.h
@@ -99,6 +99,22 @@
                                  const std::string &value) = 0;
 };
 
+// These are the functions that a RPCTask adaptor must support.
+class RPCTaskAdaptorInterface {
+ public:
+  virtual ~RPCTaskAdaptorInterface() {}
+
+  // Getter for the opaque identifier that represents this object on the
+  // RPC interface to which the implementation is adapting.
+  virtual const std::string &GetRpcIdentifier() = 0;
+
+  virtual const std::string &GetRpcInterfaceIdentifier() = 0;
+
+  // Getter for the opaque identifier that represents this object's
+  // connection to the RPC interface to which the implementation is adapting.
+  virtual const std::string &GetRpcConnectionIdentifier() = 0;
+};
+
 // These are the functions that a Service adaptor must support
 class ServiceAdaptorInterface {
  public:
diff --git a/control_interface.h b/control_interface.h
index 158695f..a2cec51 100644
--- a/control_interface.h
+++ b/control_interface.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -20,6 +20,8 @@
 class ManagerAdaptorInterface;
 class Profile;
 class ProfileAdaptorInterface;
+class RPCTask;
+class RPCTaskAdaptorInterface;
 class Service;
 class ServiceAdaptorInterface;
 
@@ -33,6 +35,7 @@
   virtual ManagerAdaptorInterface *CreateManagerAdaptor(Manager *manager) = 0;
   virtual ProfileAdaptorInterface *CreateProfileAdaptor(Profile *profile) = 0;
   virtual ServiceAdaptorInterface *CreateServiceAdaptor(Service *service) = 0;
+  virtual RPCTaskAdaptorInterface *CreateRPCTaskAdaptor(RPCTask *task) = 0;
 
   static void RpcIdToStorageId(std::string *rpc_id) {
     CHECK(rpc_id);
diff --git a/dbus_bindings/org.chromium.flimflam.Task.xml b/dbus_bindings/org.chromium.flimflam.Task.xml
new file mode 100644
index 0000000..05a87a6
--- /dev/null
+++ b/dbus_bindings/org.chromium.flimflam.Task.xml
@@ -0,0 +1,11 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+
+<node>
+	<interface name="org.chromium.flimflam.Task">
+		<method name="notify">
+			<arg type="s" direction="in"/>
+			<arg type="a{ss}" direction="in"/>
+		</method>
+	</interface>
+</node>
diff --git a/dbus_control.cc b/dbus_control.cc
index 8452c8f..64c517a 100644
--- a/dbus_control.cc
+++ b/dbus_control.cc
@@ -1,21 +1,24 @@
-// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium OS 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 "shill/dbus_control.h"
+
 #include <string>
 
 #include <base/logging.h>
 #include <dbus-c++/glib-integration.h>
 #include <dbus-c++/util.h>
 
-#include "shill/dbus_control.h"
 #include "shill/device_dbus_adaptor.h"
 #include "shill/ipconfig_dbus_adaptor.h"
 #include "shill/manager_dbus_adaptor.h"
 #include "shill/profile_dbus_adaptor.h"
+#include "shill/rpc_task_dbus_adaptor.h"
 #include "shill/service_dbus_adaptor.h"
 
 namespace shill {
+
 DBusControl::DBusControl() {}
 
 DBusControl::~DBusControl() {}
@@ -40,6 +43,11 @@
   return new(std::nothrow) ProfileDBusAdaptor(connection_.get(), profile);
 }
 
+RPCTaskAdaptorInterface *DBusControl::CreateRPCTaskAdaptor(RPCTask *task) {
+  connection_->request_name(RPCTaskDBusAdaptor::kInterfaceName);
+  return new(std::nothrow) RPCTaskDBusAdaptor(connection_.get(), task);
+}
+
 ServiceAdaptorInterface *DBusControl::CreateServiceAdaptor(Service *service) {
   connection_->request_name(ServiceDBusAdaptor::kInterfaceName);
   return new(std::nothrow) ServiceDBusAdaptor(connection_.get(), service);
diff --git a/dbus_control.h b/dbus_control.h
index a229d73..1ce72cb 100644
--- a/dbus_control.h
+++ b/dbus_control.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -22,6 +22,7 @@
   virtual IPConfigAdaptorInterface *CreateIPConfigAdaptor(IPConfig *ipconfig);
   virtual ManagerAdaptorInterface *CreateManagerAdaptor(Manager *manager);
   virtual ProfileAdaptorInterface *CreateProfileAdaptor(Profile *profile);
+  virtual RPCTaskAdaptorInterface *CreateRPCTaskAdaptor(RPCTask *task);
   virtual ServiceAdaptorInterface *CreateServiceAdaptor(Service *service);
 
   void Init();
diff --git a/mock_adaptors.cc b/mock_adaptors.cc
index 7634dfb..e94bb9e 100644
--- a/mock_adaptors.cc
+++ b/mock_adaptors.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -6,6 +6,8 @@
 
 #include <string>
 
+using std::string;
+
 namespace shill {
 
 // static
@@ -14,53 +16,73 @@
 const char DeviceMockAdaptor::kRpcConnId[] = "/device-rpc-conn/";
 
 DeviceMockAdaptor::DeviceMockAdaptor()
-    : rpc_id(kRpcId),
-      rpc_conn_id(kRpcConnId) {
+    : rpc_id_(kRpcId),
+      rpc_conn_id_(kRpcConnId) {
 }
 
 DeviceMockAdaptor::~DeviceMockAdaptor() {}
 
-const std::string &DeviceMockAdaptor::GetRpcIdentifier() { return rpc_id; }
+const string &DeviceMockAdaptor::GetRpcIdentifier() { return rpc_id_; }
 
-const std::string &DeviceMockAdaptor::GetRpcConnectionIdentifier() {
-  return rpc_conn_id;
+const string &DeviceMockAdaptor::GetRpcConnectionIdentifier() {
+  return rpc_conn_id_;
 }
 
 // static
 const char IPConfigMockAdaptor::kRpcId[] = "/ipconfig-rpc/";
 
-IPConfigMockAdaptor::IPConfigMockAdaptor() : rpc_id(kRpcId) {}
+IPConfigMockAdaptor::IPConfigMockAdaptor() : rpc_id_(kRpcId) {}
 
 IPConfigMockAdaptor::~IPConfigMockAdaptor() {}
 
-const std::string &IPConfigMockAdaptor::GetRpcIdentifier() { return rpc_id; }
+const string &IPConfigMockAdaptor::GetRpcIdentifier() { return rpc_id_; }
 
 // static
 const char ManagerMockAdaptor::kRpcId[] = "/manager-rpc/";
 
-ManagerMockAdaptor::ManagerMockAdaptor() : rpc_id(kRpcId) {}
+ManagerMockAdaptor::ManagerMockAdaptor() : rpc_id_(kRpcId) {}
 
 ManagerMockAdaptor::~ManagerMockAdaptor() {}
 
-const std::string &ManagerMockAdaptor::GetRpcIdentifier() { return rpc_id; }
+const string &ManagerMockAdaptor::GetRpcIdentifier() { return rpc_id_; }
 
 // static
 const char ProfileMockAdaptor::kRpcId[] = "/profile-rpc/";
 
-ProfileMockAdaptor::ProfileMockAdaptor() : rpc_id(kRpcId) {}
+ProfileMockAdaptor::ProfileMockAdaptor() : rpc_id_(kRpcId) {}
 
 ProfileMockAdaptor::~ProfileMockAdaptor() {}
 
-const std::string &ProfileMockAdaptor::GetRpcIdentifier() { return rpc_id; }
+const string &ProfileMockAdaptor::GetRpcIdentifier() { return rpc_id_; }
+
+// static
+const char RPCTaskMockAdaptor::kRpcId[] = "/rpc-task-rpc/";
+const char RPCTaskMockAdaptor::kRpcInterfaceId[] = "rpc.task";
+const char RPCTaskMockAdaptor::kRpcConnId[] = "/rpc-task-rpc-conn/";
+
+RPCTaskMockAdaptor::RPCTaskMockAdaptor()
+    : rpc_id_(kRpcId),
+      rpc_interface_id_(kRpcInterfaceId),
+      rpc_conn_id_(kRpcConnId) {}
+
+RPCTaskMockAdaptor::~RPCTaskMockAdaptor() {}
+
+const string &RPCTaskMockAdaptor::GetRpcIdentifier() { return rpc_id_; }
+const string &RPCTaskMockAdaptor::GetRpcInterfaceIdentifier() {
+  return rpc_interface_id_;
+}
+const string &RPCTaskMockAdaptor::GetRpcConnectionIdentifier() {
+  return rpc_conn_id_;
+}
 
 // static
 const char ServiceMockAdaptor::kRpcId[] = "/service-rpc/";
 
-ServiceMockAdaptor::ServiceMockAdaptor() : rpc_id(kRpcId) {}
+ServiceMockAdaptor::ServiceMockAdaptor() : rpc_id_(kRpcId) {}
 
 ServiceMockAdaptor::~ServiceMockAdaptor() {}
 
-const std::string &ServiceMockAdaptor::GetRpcIdentifier() { return rpc_id; }
+const string &ServiceMockAdaptor::GetRpcIdentifier() { return rpc_id_; }
 
 MockReturner::MockReturner() {}
 
diff --git a/mock_adaptors.h b/mock_adaptors.h
index a190192..2380733 100644
--- a/mock_adaptors.h
+++ b/mock_adaptors.h
@@ -37,8 +37,8 @@
                                               const KeyValueStore &value));
 
  private:
-  const std::string rpc_id;
-  const std::string rpc_conn_id;
+  const std::string rpc_id_;
+  const std::string rpc_conn_id_;
 };
 
 // These are the functions that a IPConfig adaptor must support
@@ -56,7 +56,7 @@
   MOCK_METHOD2(EmitStringChanged, void(const std::string&, const std::string&));
 
  private:
-  const std::string rpc_id;
+  const std::string rpc_id_;
 };
 
 // These are the functions that a Manager adaptor must support
@@ -81,7 +81,7 @@
   MOCK_METHOD1(EmitStateChanged, void(const std::string&));
 
  private:
-  const std::string rpc_id;
+  const std::string rpc_id_;
 };
 
 // These are the functions that a Profile adaptor must support
@@ -99,7 +99,27 @@
   MOCK_METHOD2(EmitStringChanged, void(const std::string&, const std::string&));
 
  private:
-  const std::string rpc_id;
+  const std::string rpc_id_;
+};
+
+// These are the functions that a Task adaptor must support
+class RPCTaskMockAdaptor : public RPCTaskAdaptorInterface {
+ public:
+  static const char kRpcId[];
+  static const char kRpcInterfaceId[];
+  static const char kRpcConnId[];
+
+  RPCTaskMockAdaptor();
+  virtual ~RPCTaskMockAdaptor();
+
+  virtual const std::string &GetRpcIdentifier();
+  virtual const std::string &GetRpcInterfaceIdentifier();
+  virtual const std::string &GetRpcConnectionIdentifier();
+
+ private:
+  const std::string rpc_id_;
+  const std::string rpc_interface_id_;
+  const std::string rpc_conn_id_;
 };
 
 // These are the functions that a Service adaptor must support
@@ -123,7 +143,7 @@
                void(const std::string &name, const Stringmap &value));
 
  private:
-  const std::string rpc_id;
+  const std::string rpc_id_;
 };
 
 class MockReturner : public ReturnerInterface {
diff --git a/mock_control.cc b/mock_control.cc
index cb72fb7..d4d638e 100644
--- a/mock_control.cc
+++ b/mock_control.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -31,6 +31,10 @@
   return new ProfileMockAdaptor();
 }
 
+RPCTaskAdaptorInterface *MockControl::CreateRPCTaskAdaptor(RPCTask */*task*/) {
+  return new RPCTaskMockAdaptor();
+}
+
 ServiceAdaptorInterface *MockControl::CreateServiceAdaptor(
     Service */*service*/) {
   return new ServiceMockAdaptor();
diff --git a/mock_control.h b/mock_control.h
index ef0682a..d351301 100644
--- a/mock_control.h
+++ b/mock_control.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -23,6 +23,7 @@
   virtual IPConfigAdaptorInterface *CreateIPConfigAdaptor(IPConfig *config);
   virtual ManagerAdaptorInterface *CreateManagerAdaptor(Manager *manager);
   virtual ProfileAdaptorInterface *CreateProfileAdaptor(Profile *profile);
+  virtual RPCTaskAdaptorInterface *CreateRPCTaskAdaptor(RPCTask *task);
   virtual ServiceAdaptorInterface *CreateServiceAdaptor(Service *service);
 
  private:
diff --git a/nice_mock_control.cc b/nice_mock_control.cc
index 26d0af4..32f031a 100644
--- a/nice_mock_control.cc
+++ b/nice_mock_control.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -36,6 +36,11 @@
   return new NiceMock<ProfileMockAdaptor>();
 }
 
+RPCTaskAdaptorInterface *NiceMockControl::CreateRPCTaskAdaptor(
+    RPCTask */*task*/) {
+  return new NiceMock<RPCTaskMockAdaptor>();
+}
+
 ServiceAdaptorInterface *NiceMockControl::CreateServiceAdaptor(
     Service */*service*/) {
   return new NiceMock<ServiceMockAdaptor>();
diff --git a/nice_mock_control.h b/nice_mock_control.h
index b8686f4..bbfbded 100644
--- a/nice_mock_control.h
+++ b/nice_mock_control.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -23,6 +23,7 @@
   virtual IPConfigAdaptorInterface *CreateIPConfigAdaptor(IPConfig *config);
   virtual ManagerAdaptorInterface *CreateManagerAdaptor(Manager *manager);
   virtual ProfileAdaptorInterface *CreateProfileAdaptor(Profile *profile);
+  virtual RPCTaskAdaptorInterface *CreateRPCTaskAdaptor(RPCTask *task);
   virtual ServiceAdaptorInterface *CreateServiceAdaptor(Service *service);
 
  private:
diff --git a/openvpn_driver.cc b/openvpn_driver.cc
index e50335d..166e79c 100644
--- a/openvpn_driver.cc
+++ b/openvpn_driver.cc
@@ -8,18 +8,26 @@
 #include <chromeos/dbus/service_constants.h>
 
 #include "shill/error.h"
+#include "shill/rpc_task.h"
 
 using std::string;
 using std::vector;
 
 namespace shill {
 
-OpenVPNDriver::OpenVPNDriver(const KeyValueStore &args)
-    : args_(args) {}
+namespace {
+const char kOpenVPNScript[] = "/usr/lib/flimflam/scripts/openvpn-script";
+}  // namespace {}
+
+OpenVPNDriver::OpenVPNDriver(ControlInterface *control,
+                             const KeyValueStore &args)
+    : control_(control),
+      args_(args) {}
 
 OpenVPNDriver::~OpenVPNDriver() {}
 
 void OpenVPNDriver::Connect(Error *error) {
+  // TODO(petkov): Allocate rpc_task_.
   error->Populate(Error::kNotSupported);
 }
 
@@ -121,8 +129,22 @@
   // TODO(petkov): Setup management control channel and add the approprate
   // options (crosbug.com/26994).
 
-  // TODO(petkov): Setup openvpn-script options and DBus info required to send
-  // back Layer 3 configuration (crosbug.com/26993).
+  // Setup openvpn-script options and RPC information required to send back
+  // Layer 3 configuration.
+  options->push_back("--setenv");
+  options->push_back("CONNMAN_BUSNAME");
+  options->push_back(rpc_task_->GetRpcConnectionIdentifier());
+  options->push_back("--setenv");
+  options->push_back("CONNMAN_INTERFACE");
+  options->push_back(rpc_task_->GetRpcInterfaceIdentifier());
+  options->push_back("--setenv");
+  options->push_back("CONNMAN_PATH");
+  options->push_back(rpc_task_->GetRpcIdentifier());
+  options->push_back("--script-security");
+  options->push_back("2");
+  options->push_back("--up");
+  options->push_back(kOpenVPNScript);
+  options->push_back("--up-restart");
 
   // Disable openvpn handling since we do route+ifconfig work.
   options->push_back("--route-noexec");
diff --git a/openvpn_driver.h b/openvpn_driver.h
index ea4b4c9..9a07652 100644
--- a/openvpn_driver.h
+++ b/openvpn_driver.h
@@ -8,6 +8,7 @@
 #include <string>
 #include <vector>
 
+#include <base/memory/scoped_ptr.h>
 #include <gtest/gtest_prod.h>  // for FRIEND_TEST
 
 #include "shill/key_value_store.h"
@@ -15,11 +16,13 @@
 
 namespace shill {
 
+class ControlInterface;
 class Error;
+class RPCTask;
 
 class OpenVPNDriver : public VPNDriver {
  public:
-  explicit OpenVPNDriver(const KeyValueStore &args);
+  OpenVPNDriver(ControlInterface *control, const KeyValueStore &args);
   virtual ~OpenVPNDriver();
 
   // Inherited from VPNDriver.
@@ -41,7 +44,9 @@
                   const std::string &option,
                   std::vector<std::string> *options);
 
+  ControlInterface *control_;
   KeyValueStore args_;
+  scoped_ptr<RPCTask> rpc_task_;
 
   DISALLOW_COPY_AND_ASSIGN(OpenVPNDriver);
 };
diff --git a/openvpn_driver_unittest.cc b/openvpn_driver_unittest.cc
index e757461..cedc0f7 100644
--- a/openvpn_driver_unittest.cc
+++ b/openvpn_driver_unittest.cc
@@ -4,23 +4,33 @@
 
 #include "shill/openvpn_driver.h"
 
+#include <algorithm>
+
 #include <chromeos/dbus/service_constants.h>
 #include <gtest/gtest.h>
 
 #include "shill/error.h"
+#include "shill/mock_adaptors.h"
+#include "shill/nice_mock_control.h"
+#include "shill/rpc_task.h"
 
+using std::map;
 using std::string;
 using std::vector;
 
 namespace shill {
 
-class OpenVPNDriverTest : public testing::Test {
+class OpenVPNDriverTest : public testing::Test,
+                          public RPCTaskDelegate {
  public:
   OpenVPNDriverTest()
-      : driver_(args_) {}
+      : driver_(&control_, args_) {}
 
   virtual ~OpenVPNDriverTest() {}
 
+  // Inherited from RPCTaskDelegate.
+  virtual void Notify(const string &reason, const map<string, string> &dict);
+
  protected:
   static const char kOption[];
   static const char kProperty[];
@@ -33,6 +43,7 @@
     driver_.args_ = args_;
   }
 
+  NiceMockControl control_;
   KeyValueStore args_;
   OpenVPNDriver driver_;
 };
@@ -44,6 +55,9 @@
 const char OpenVPNDriverTest::kProperty2[] = "OpenVPN.SomeProperty2";
 const char OpenVPNDriverTest::kValue2[] = "some-property-value2";
 
+void OpenVPNDriverTest::Notify(const string &/*reason*/,
+                               const map<string, string> &/*dict*/) {}
+
 TEST_F(OpenVPNDriverTest, Connect) {
   Error error;
   driver_.Connect(&error);
@@ -62,6 +76,7 @@
   static const char kHost[] = "192.168.2.254";
   args_.SetString(flimflam::kProviderHostProperty, kHost);
   SetArgs();
+  driver_.rpc_task_.reset(new RPCTask(&control_, this));
   Error error;
   vector<string> options;
   driver_.InitOptions(&options, &error);
@@ -70,6 +85,9 @@
   EXPECT_EQ("--remote", options[2]);
   EXPECT_EQ(kHost, options[3]);
   EXPECT_EQ("openvpn", options.back());
+  EXPECT_TRUE(
+      std::find(options.begin(), options.end(), RPCTaskMockAdaptor::kRpcId) !=
+      options.end());
 }
 
 TEST_F(OpenVPNDriverTest, AppendValueOption) {
diff --git a/rpc_task.cc b/rpc_task.cc
new file mode 100644
index 0000000..dd8b81b
--- /dev/null
+++ b/rpc_task.cc
@@ -0,0 +1,48 @@
+// Copyright (c) 2012 The Chromium OS 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 "shill/rpc_task.h"
+
+#include <base/string_number_conversions.h>
+
+#include "shill/adaptor_interfaces.h"
+#include "shill/control_interface.h"
+
+using std::map;
+using std::string;
+
+namespace shill {
+
+// static
+unsigned int RPCTask::serial_number_ = 0;
+
+RPCTask::RPCTask(ControlInterface *control_interface, RPCTaskDelegate *delegate)
+    : delegate_(delegate),
+      unique_name_(base::UintToString(serial_number_++)),
+      adaptor_(control_interface->CreateRPCTaskAdaptor(this)) {
+  CHECK(delegate);
+  VLOG(2) << "RPCTask " + unique_name_ + " created.";
+}
+
+RPCTask::~RPCTask() {
+  VLOG(2) << "RPCTask " + unique_name_ + " destroyed.";
+}
+
+void RPCTask::Notify(const string &reason, const map<string, string> &dict) {
+  delegate_->Notify(reason, dict);
+}
+
+string RPCTask::GetRpcIdentifier() const {
+  return adaptor_->GetRpcIdentifier();
+}
+
+string RPCTask::GetRpcInterfaceIdentifier() const {
+  return adaptor_->GetRpcInterfaceIdentifier();
+}
+
+string RPCTask::GetRpcConnectionIdentifier() const {
+  return adaptor_->GetRpcConnectionIdentifier();
+}
+
+}  // namespace shill
diff --git a/rpc_task.h b/rpc_task.h
new file mode 100644
index 0000000..13fe814
--- /dev/null
+++ b/rpc_task.h
@@ -0,0 +1,58 @@
+// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SHILL_RPC_TASK_
+#define SHILL_RPC_TASK_
+
+#include <map>
+#include <string>
+
+#include <base/basictypes.h>
+#include <base/memory/scoped_ptr.h>
+
+namespace shill {
+
+class ControlInterface;
+class RPCTaskAdaptorInterface;
+
+class RPCTaskDelegate {
+ public:
+  virtual ~RPCTaskDelegate() {}
+
+  virtual void Notify(const std::string &reason,
+                      const std::map<std::string, std::string> &dict) = 0;
+};
+
+// RPC tasks are currently used by VPN drivers for communication with external
+// VPN processes. The RPC task should be owned by a single owner -- its
+// RPCTaskDelegate -- so no need to be reference counted.
+class RPCTask {
+ public:
+  // A constructor for the RPCTask object.
+  RPCTask(ControlInterface *control_interface, RPCTaskDelegate *delegate);
+  virtual ~RPCTask();
+
+  virtual void Notify(const std::string &reason,
+                      const std::map<std::string, std::string> &dict);
+
+  // Returns a string that is guaranteed to uniquely identify this RPCTask
+  // instance.
+  const std::string &UniqueName() const { return unique_name_; }
+
+  std::string GetRpcIdentifier() const;
+  std::string GetRpcInterfaceIdentifier() const;
+  std::string GetRpcConnectionIdentifier() const;
+
+ private:
+  RPCTaskDelegate *delegate_;
+  static unsigned int serial_number_;
+  std::string unique_name_;  // MUST be unique amongst RPC task instances
+  scoped_ptr<RPCTaskAdaptorInterface> adaptor_;
+
+  DISALLOW_COPY_AND_ASSIGN(RPCTask);
+};
+
+}  // namespace shill
+
+#endif  // SHILL_RPC_TASK_
diff --git a/rpc_task_dbus_adaptor.cc b/rpc_task_dbus_adaptor.cc
new file mode 100644
index 0000000..42364c4
--- /dev/null
+++ b/rpc_task_dbus_adaptor.cc
@@ -0,0 +1,53 @@
+// Copyright (c) 2012 The Chromium OS 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 "shill/rpc_task_dbus_adaptor.h"
+
+#include <base/logging.h>
+
+#include "shill/error.h"
+#include "shill/rpc_task.h"
+
+using std::map;
+using std::string;
+
+namespace shill {
+
+// static
+const char RPCTaskDBusAdaptor::kInterfaceName[] = SHILL_INTERFACE;
+// static
+const char RPCTaskDBusAdaptor::kPath[] = "/task/";
+
+RPCTaskDBusAdaptor::RPCTaskDBusAdaptor(DBus::Connection *conn, RPCTask *task)
+    : DBusAdaptor(conn, kPath + task->UniqueName()),
+      task_(task),
+      interface_name_(string(kInterfaceName) + ".Task"),
+      connection_name_(conn->unique_name()) {}
+
+RPCTaskDBusAdaptor::~RPCTaskDBusAdaptor() {
+  task_ = NULL;
+}
+
+const string &RPCTaskDBusAdaptor::GetRpcIdentifier() {
+  return DBus::Object::path();
+}
+
+const string &RPCTaskDBusAdaptor::GetRpcInterfaceIdentifier() {
+  // TODO(petkov): We should be able to return DBus::Interface::name() or simply
+  // name() and avoid the need for the |interface_name_| data member. However,
+  // that's non-trivial due to multiple inheritance (crosbug.com/27058).
+  return interface_name_;
+}
+
+const string &RPCTaskDBusAdaptor::GetRpcConnectionIdentifier() {
+  return connection_name_;
+}
+
+void RPCTaskDBusAdaptor::notify(const string &reason,
+                                const map<string, string> &dict,
+                                DBus::Error &/*error*/) {
+  task_->Notify(reason, dict);
+}
+
+}  // namespace shill
diff --git a/rpc_task_dbus_adaptor.h b/rpc_task_dbus_adaptor.h
new file mode 100644
index 0000000..1ef026b
--- /dev/null
+++ b/rpc_task_dbus_adaptor.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SHILL_RPC_TASK_DBUS_ADAPTOR_H_
+#define SHILL_RPC_TASK_DBUS_ADAPTOR_H_
+
+#include <base/basictypes.h>
+
+#include "shill/adaptor_interfaces.h"
+#include "shill/dbus_adaptor.h"
+#include "shill/dbus_bindings/flimflam-task.h"
+
+namespace shill {
+
+class RPCTask;
+
+// Subclass of DBusAdaptor for RPCTask objects. There is a 1:1 mapping between
+// RPCTask and RPCTaskDBusAdaptor instances. Furthermore, the RPCTask owns the
+// RPCTaskDBusAdaptor and manages its lifetime, so we're OK with
+// RPCTaskDBusAdaptor having a bare pointer to its owner task.
+class RPCTaskDBusAdaptor : public org::chromium::flimflam::Task_adaptor,
+                           public DBusAdaptor,
+                           public RPCTaskAdaptorInterface {
+ public:
+  static const char kInterfaceName[];
+  static const char kPath[];
+
+  RPCTaskDBusAdaptor(DBus::Connection *conn, RPCTask *task);
+  virtual ~RPCTaskDBusAdaptor();
+
+  // Implementation of RPCTaskAdaptorInterface.
+  virtual const std::string &GetRpcIdentifier();
+  virtual const std::string &GetRpcInterfaceIdentifier();
+  virtual const std::string &GetRpcConnectionIdentifier();
+
+  // Implementation of Task_adaptor
+  virtual void notify(const std::string &reason,
+                      const std::map<std::string, std::string> &dict,
+                      DBus::Error &error);
+
+ private:
+  RPCTask *task_;
+  const std::string interface_name_;
+  const std::string connection_name_;
+
+  DISALLOW_COPY_AND_ASSIGN(RPCTaskDBusAdaptor);
+};
+
+}  // namespace shill
+
+#endif  // SHILL_RPC_TASK_DBUS_ADAPTOR_H_
diff --git a/rpc_task_unittest.cc b/rpc_task_unittest.cc
new file mode 100644
index 0000000..8788502
--- /dev/null
+++ b/rpc_task_unittest.cc
@@ -0,0 +1,58 @@
+// Copyright (c) 2012 The Chromium OS 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 "shill/rpc_task.h"
+
+#include <gtest/gtest.h>
+
+#include "shill/nice_mock_control.h"
+#include "shill/mock_adaptors.h"
+
+using std::map;
+using std::string;
+
+namespace shill {
+
+class RPCTaskTest : public testing::Test,
+                    public RPCTaskDelegate {
+ public:
+  RPCTaskTest() : notify_calls_(0), task_(&control_, this) {}
+
+  // Inherited from RPCTaskDelegate.
+  virtual void Notify(const string &reason, const map<string, string> &dict);
+
+ protected:
+  int notify_calls_;
+  string last_notify_reason_;
+  map<string, string> last_notify_dict_;
+  NiceMockControl control_;
+  RPCTask task_;
+};
+
+void RPCTaskTest::Notify(const string &reason,
+                         const map<string, string> &dict) {
+
+  notify_calls_++;
+  last_notify_reason_ = reason;
+  last_notify_dict_ = dict;
+}
+
+TEST_F(RPCTaskTest, GetRpcIdentifiers) {
+  EXPECT_EQ(RPCTaskMockAdaptor::kRpcId, task_.GetRpcIdentifier());
+  EXPECT_EQ(RPCTaskMockAdaptor::kRpcInterfaceId,
+            task_.GetRpcInterfaceIdentifier());
+  EXPECT_EQ(RPCTaskMockAdaptor::kRpcConnId, task_.GetRpcConnectionIdentifier());
+}
+
+TEST_F(RPCTaskTest, Notify) {
+  static const char kReason[] = "up";
+  map<string, string> dict;
+  dict["foo"] = "bar";
+  task_.Notify(kReason, dict);
+  EXPECT_EQ(1, notify_calls_);
+  EXPECT_EQ(kReason, last_notify_reason_);
+  EXPECT_EQ("bar", last_notify_dict_["foo"]);
+}
+
+}  // namespace shill
diff --git a/vpn_provider.cc b/vpn_provider.cc
index 951e165..84903f7 100644
--- a/vpn_provider.cc
+++ b/vpn_provider.cc
@@ -41,7 +41,7 @@
   const string &type = args.GetString(flimflam::kProviderTypeProperty);
   scoped_ptr<VPNDriver> driver;
   if (type == flimflam::kProviderOpenVpn) {
-    driver.reset(new OpenVPNDriver(args));
+    driver.reset(new OpenVPNDriver(control_interface_, args));
   } else {
     Error::PopulateAndLog(
         error, Error::kNotSupported, "Unsupported VPN type: " + type);