1 //
2 // Copyright (C) 2012 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 
17 #ifndef SHILL_DHCP_DHCP_PROVIDER_H_
18 #define SHILL_DHCP_DHCP_PROVIDER_H_
19 
20 #include <map>
21 #include <memory>
22 #include <set>
23 #include <string>
24 
25 #include <base/files/file_path.h>
26 #include <base/lazy_instance.h>
27 #include <gtest/gtest_prod.h>  // for FRIEND_TEST
28 
29 #include "shill/dhcp_properties.h"
30 #include "shill/refptr_types.h"
31 
32 namespace shill {
33 
34 class ControlInterface;
35 class DHCPCDListenerInterface;
36 class EventDispatcher;
37 class Metrics;
38 
39 // DHCPProvider is a singleton providing the main DHCP configuration
40 // entrypoint. Once the provider is initialized through its Init method, DHCP
41 // configurations for devices can be obtained through its CreateConfig
42 // method. For example, a single DHCP configuration request can be initiated as:
43 //
44 // DHCPProvider::GetInstance()->CreateIPv4Config(device_name,
45 //                                               lease_file_suffix,
46 //                                               arp_gateway,
47 //                                               dhcp_props)->Request();
48 class DHCPProvider {
49  public:
50   static constexpr char kDHCPCDPathFormatLease[] =
51       "var/lib/dhcpcd/dhcpcd-%s.lease";
52 #ifndef DISABLE_DHCPV6
53   static constexpr char kDHCPCDPathFormatLease6[] =
54       "var/lib/dhcpcd/dhcpcd-%s.lease6";
55 #endif  // DISABLE_DHCPV6
56 
57   virtual ~DHCPProvider();
58 
59   // This is a singleton -- use DHCPProvider::GetInstance()->Foo().
60   static DHCPProvider* GetInstance();
61 
62   // Initializes the provider singleton. This method hooks up a D-Bus signal
63   // listener that catches signals from spawned DHCP clients and dispatches them
64   // to the appropriate DHCP configuration instance.
65   virtual void Init(ControlInterface* control_interface,
66                     EventDispatcher* dispatcher,
67                     Metrics* metrics);
68 
69   // Called on shutdown to release |listener_|.
70   void Stop();
71 
72   // Creates a new DHCPv4Config for |device_name|. The DHCP configuration for
73   // the device can then be initiated through DHCPConfig::Request and
74   // DHCPConfig::Renew.  If |host_name| is not-empty, it is placed in the DHCP
75   // request to allow the server to map the request to a specific user-named
76   // origin.  The DHCP lease file will contain the suffix supplied
77   // in |lease_file_suffix| if non-empty, otherwise |device_name|.  If
78   // |arp_gateway| is true, the DHCP client will ARP for the gateway IP
79   // address as an additional safeguard against the issued IP address being
80   // in-use by another station.
81   virtual DHCPConfigRefPtr CreateIPv4Config(
82       const std::string& device_name,
83       const std::string& lease_file_suffix,
84       bool arp_gateway,
85       const DhcpProperties& dhcp_props);
86 
87 #ifndef DISABLE_DHCPV6
88   // Create a new DHCPv6Config for |device_name|.
89   virtual DHCPConfigRefPtr CreateIPv6Config(
90       const std::string& device_name, const std::string& lease_file_suffix);
91 #endif
92 
93   // Returns the DHCP configuration associated with DHCP client |pid|. Return
94   // nullptr if |pid| is not bound to a configuration.
95   DHCPConfigRefPtr GetConfig(int pid);
96 
97   // Binds a |pid| to a DHCP |config|. When a DHCP config spawns a new DHCP
98   // client, it binds itself to that client's |pid|.
99   virtual void BindPID(int pid, const DHCPConfigRefPtr& config);
100 
101   // Unbinds a |pid|. This method is used by a DHCP config to signal the
102   // provider that the DHCP client has been terminated. This may result in
103   // destruction of the DHCP config instance if its reference count goes to 0.
104   virtual void UnbindPID(int pid);
105 
106   // Destroy lease file associated with this |name|.
107   virtual void DestroyLease(const std::string& name);
108 
109   // Returns true if |pid| was recently unbound from the provider.
110   bool IsRecentlyUnbound(int pid);
111 
112  protected:
113   DHCPProvider();
114 
115  private:
116   friend struct base::DefaultLazyInstanceTraits<DHCPProvider>;
117   friend class CellularTest;
118   friend class DHCPProviderTest;
119   friend class DeviceInfoTest;
120   friend class DeviceTest;
121   FRIEND_TEST(DHCPProviderTest, CreateIPv4Config);
122   FRIEND_TEST(DHCPProviderTest, DestroyLease);
123 
124   typedef std::map<int, DHCPConfigRefPtr> PIDConfigMap;
125 
126   // Retire |pid| from the set of recently retired PIDs.
127   void RetireUnboundPID(int pid);
128 
129   // A single listener is used to catch signals from all DHCP clients and
130   // dispatch them to the appropriate DHCP configuration instance.
131   std::unique_ptr<DHCPCDListenerInterface> listener_;
132 
133   // A map that binds PIDs to DHCP configuration instances.
134   PIDConfigMap configs_;
135 
136   base::FilePath root_;
137   ControlInterface* control_interface_;
138   EventDispatcher* dispatcher_;
139   Metrics* metrics_;
140 
141   // Track the set of PIDs recently unbound from the provider in case messages
142   // arrive addressed from them.
143   std::set<int> recently_unbound_pids_;
144 
145   DISALLOW_COPY_AND_ASSIGN(DHCPProvider);
146 };
147 
148 }  // namespace shill
149 
150 #endif  // SHILL_DHCP_DHCP_PROVIDER_H_
151