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
32namespace shill {
33
34class ControlInterface;
35class DHCPCDListenerInterface;
36class EventDispatcher;
37class 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();
48class 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