Kea  2.1.7-git
csv_lease_file4.cc
Go to the documentation of this file.
1 // Copyright (C) 2014-2020 Internet Systems Consortium, Inc. ("ISC")
2 //
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 
7 #include <config.h>
9 #include <ctime>
10 
11 using namespace isc::asiolink;
12 using namespace isc::data;
13 using namespace isc::util;
14 
15 namespace isc {
16 namespace dhcp {
17 
18 CSVLeaseFile4::CSVLeaseFile4(const std::string& filename)
19  : VersionedCSVFile(filename) {
20  initColumns();
21 }
22 
23 void
24 CSVLeaseFile4::open(const bool seek_to_end) {
25  // Call the base class to open the file
26  VersionedCSVFile::open(seek_to_end);
27 
28  // and clear any statistics we may have
30 }
31 
32 void
34  // Bump the number of write attempts
35  ++writes_;
36 
37  CSVRow row(getColumnCount());
38  row.writeAt(getColumnIndex("address"), lease.addr_.toText());
39 
40  if (((!lease.hwaddr_) || lease.hwaddr_->hwaddr_.empty()) &&
41  ((!lease.client_id_) || (lease.client_id_->getClientId().empty())) &&
42  (lease.state_ != Lease::STATE_DECLINED)) {
43  // Bump the error counter
44  ++write_errs_;
45 
46  isc_throw(BadValue, "Lease4: " << lease.addr_.toText() << ", state: "
48  << " has neither hardware address or client id");
49 
50  }
51 
52  // Hardware addr may be unset (NULL).
53  if (lease.hwaddr_) {
54  row.writeAt(getColumnIndex("hwaddr"), lease.hwaddr_->toText(false));
55  }
56 
57  // Client id may be unset (NULL).
58  if (lease.client_id_) {
59  row.writeAt(getColumnIndex("client_id"), lease.client_id_->toText());
60  }
61 
62  row.writeAt(getColumnIndex("valid_lifetime"), lease.valid_lft_);
63  row.writeAt(getColumnIndex("expire"), static_cast<uint64_t>(lease.cltt_) + lease.valid_lft_);
64  row.writeAt(getColumnIndex("subnet_id"), lease.subnet_id_);
65  row.writeAt(getColumnIndex("fqdn_fwd"), lease.fqdn_fwd_);
66  row.writeAt(getColumnIndex("fqdn_rev"), lease.fqdn_rev_);
67  row.writeAtEscaped(getColumnIndex("hostname"), lease.hostname_);
68  row.writeAt(getColumnIndex("state"), lease.state_);
69  // User context is optional.
70  if (lease.getContext()) {
71  row.writeAtEscaped(getColumnIndex("user_context"), lease.getContext()->str());
72  }
73 
74  try {
75  VersionedCSVFile::append(row);
76  } catch (const std::exception&) {
77  // Catch any errors so we can bump the error counter than rethrow it
78  ++write_errs_;
79  throw;
80  }
81 
82  // Bump the number of leases written
83  ++write_leases_;
84 }
85 
86 bool
88  // Bump the number of read attempts
89  ++reads_;
90 
91  // Read the CSV row and try to create a lease from the values read.
92  // This may easily result in exception. We don't want this function
93  // to throw exceptions, so we catch them all and rather return the
94  // false value.
95  try {
96  // Get the row of CSV values.
97  CSVRow row;
98  VersionedCSVFile::next(row);
99  // The empty row signals EOF.
100  if (row == CSVFile::EMPTY_ROW()) {
101  lease.reset();
102  return (true);
103  }
104 
105  // Get the lease address.
106  IOAddress addr(readAddress(row));
107 
108  // Get client id. It is possible that the client id is empty and the
109  // returned pointer is NULL. This is ok, but if the client id is NULL,
110  // we need to be careful to not use the NULL pointer.
111  ClientIdPtr client_id = readClientId(row);
112  std::vector<uint8_t> client_id_vec;
113  if (client_id) {
114  client_id_vec = client_id->getClientId();
115  }
116  size_t client_id_len = client_id_vec.size();
117 
118  // Get the HW address. It should never be empty and the readHWAddr checks
119  // that.
120  HWAddr hwaddr = readHWAddr(row);
121  uint32_t state = readState(row);
122 
123  if ((hwaddr.hwaddr_.empty()) && (client_id_vec.empty()) &&
124  (state != Lease::STATE_DECLINED)) {
125  isc_throw(BadValue, "Lease4: " << addr.toText() << ", state: "
126  << Lease::basicStatesToText(state)
127  << " has neither hardware address or client id");
128  }
129 
130  // Get the user context (can be NULL).
131  ConstElementPtr ctx = readContext(row);
132 
133  lease.reset(new Lease4(addr,
134  HWAddrPtr(new HWAddr(hwaddr)),
135  client_id_vec.empty() ? NULL : &client_id_vec[0],
136  client_id_len,
137  readValid(row),
138  readCltt(row),
139  readSubnetID(row),
140  readFqdnFwd(row),
141  readFqdnRev(row),
142  readHostname(row)));
143  lease->state_ = state;
144 
145  if (ctx) {
146  lease->setContext(ctx);
147  }
148 
149  } catch (const std::exception& ex) {
150  // bump the read error count
151  ++read_errs_;
152 
153  // The lease might have been created, so let's set it back to NULL to
154  // signal that lease hasn't been parsed.
155  lease.reset();
156  setReadMsg(ex.what());
157  return (false);
158  }
159 
160  // bump the number of leases read
161  ++read_leases_;
162 
163  return (true);
164 }
165 
166 void
167 CSVLeaseFile4::initColumns() {
168  addColumn("address", "1.0");
169  addColumn("hwaddr", "1.0");
170  addColumn("client_id", "1.0");
171  addColumn("valid_lifetime", "1.0");
172  addColumn("expire", "1.0");
173  addColumn("subnet_id", "1.0");
174  addColumn("fqdn_fwd", "1.0");
175  addColumn("fqdn_rev", "1.0");
176  addColumn("hostname", "1.0");
177  addColumn("state", "2.0", "0");
178  addColumn("user_context", "2.1");
179  // Any file with less than hostname is invalid
180  setMinimumValidColumns("hostname");
181 }
182 
183 IOAddress
184 CSVLeaseFile4::readAddress(const CSVRow& row) {
185  IOAddress address(row.readAt(getColumnIndex("address")));
186  return (address);
187 }
188 
189 HWAddr
190 CSVLeaseFile4::readHWAddr(const CSVRow& row) {
191  HWAddr hwaddr = HWAddr::fromText(row.readAt(getColumnIndex("hwaddr")));
192  return (hwaddr);
193 }
194 
196 CSVLeaseFile4::readClientId(const CSVRow& row) {
197  std::string client_id = row.readAt(getColumnIndex("client_id"));
198  // NULL client ids are allowed in DHCPv4.
199  if (client_id.empty()) {
200  return (ClientIdPtr());
201  }
202  ClientIdPtr cid = ClientId::fromText(client_id);
203  return (cid);
204 }
205 
206 uint32_t
207 CSVLeaseFile4::readValid(const CSVRow& row) {
208  uint32_t valid =
209  row.readAndConvertAt<uint32_t>(getColumnIndex("valid_lifetime"));
210  return (valid);
211 }
212 
213 time_t
214 CSVLeaseFile4::readCltt(const CSVRow& row) {
215  time_t cltt =
216  static_cast<time_t>(row.readAndConvertAt<uint64_t>(getColumnIndex("expire"))
217  - readValid(row));
218  return (cltt);
219 }
220 
221 SubnetID
222 CSVLeaseFile4::readSubnetID(const CSVRow& row) {
223  SubnetID subnet_id =
224  row.readAndConvertAt<SubnetID>(getColumnIndex("subnet_id"));
225  return (subnet_id);
226 }
227 
228 bool
229 CSVLeaseFile4::readFqdnFwd(const CSVRow& row) {
230  bool fqdn_fwd = row.readAndConvertAt<bool>(getColumnIndex("fqdn_fwd"));
231  return (fqdn_fwd);
232 }
233 
234 bool
235 CSVLeaseFile4::readFqdnRev(const CSVRow& row) {
236  bool fqdn_rev = row.readAndConvertAt<bool>(getColumnIndex("fqdn_rev"));
237  return (fqdn_rev);
238 }
239 
240 std::string
241 CSVLeaseFile4::readHostname(const CSVRow& row) {
242  std::string hostname = row.readAtEscaped(getColumnIndex("hostname"));
243  return (hostname);
244 }
245 
246 uint32_t
247 CSVLeaseFile4::readState(const util::CSVRow& row) {
248  uint32_t state = row.readAndConvertAt<uint32_t>(getColumnIndex("state"));
249  return (state);
250 }
251 
253 CSVLeaseFile4::readContext(const util::CSVRow& row) {
254  std::string user_context = row.readAtEscaped(getColumnIndex("user_context"));
255  if (user_context.empty()) {
256  return (ConstElementPtr());
257  }
258  ConstElementPtr ctx = Element::fromJSON(user_context);
259  if (!ctx || (ctx->getType() != Element::map)) {
260  isc_throw(isc::BadValue, "user context '" << user_context
261  << "' is not a JSON map");
262  }
263  return (ctx);
264 }
265 
266 } // end of namespace isc::dhcp
267 } // end of namespace isc
T readAndConvertAt(const size_t at) const
Retrieves a value from the internal container.
Definition: csv_file.h:156
uint32_t state_
Holds the lease state(s).
Definition: lease.h:179
static ClientIdPtr fromText(const std::string &text)
Create client identifier from the textual format.
Definition: duid.cc:132
HWAddrPtr hwaddr_
Client&#39;s MAC/hardware address.
Definition: lease.h:168
size_t getColumnCount() const
Returns the number of columns in the file.
Definition: csv_file.h:403
Structure that holds a lease for IPv4 address.
Definition: lease.h:289
data::ConstElementPtr getContext() const
Returns const pointer to the user context.
Definition: user_context.h:24
bool fqdn_rev_
Reverse zone updated?
Definition: lease.h:163
uint32_t reads_
Number of attempts to read a lease.
boost::shared_ptr< HWAddr > HWAddrPtr
Shared pointer to a hardware address structure.
Definition: hwaddr.h:154
bool next(Lease4Ptr &lease)
Reads next lease from the CSV file.
void writeAtEscaped(const size_t at, const std::string &value)
Replaces the value at the specified index with a value that has had special characters escaped...
Definition: csv_file.cc:90
time_t cltt_
Client last transmission time.
Definition: lease.h:137
bool fqdn_fwd_
Forward zone updated?
Definition: lease.h:158
uint32_t writes_
Number of attempts to write a lease.
std::vector< uint8_t > hwaddr_
Definition: hwaddr.h:98
uint32_t write_leases_
Number of lease written.
std::string hostname_
Client hostname.
Definition: lease.h:153
SubnetID subnet_id_
Subnet identifier.
Definition: lease.h:148
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
Definition: edns.h:19
boost::shared_ptr< Lease4 > Lease4Ptr
Pointer to a Lease4 structure.
Definition: lease.h:278
void setMinimumValidColumns(const std::string &column_name)
Sets the minimum number of valid columns based on a given column.
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:27
Represents a single row of the CSV file.
Definition: csv_file.h:51
void setReadMsg(const std::string &read_msg)
Sets error message after row validation.
Definition: csv_file.h:486
ClientIdPtr client_id_
Client identifier.
Definition: lease.h:295
boost::shared_ptr< ClientId > ClientIdPtr
Shared pointer to a Client ID.
Definition: duid.h:103
void clearStatistics()
Clears the statistics.
uint32_t write_errs_
Number of errors when writing.
Defines the logger used by the top-level component of kea-lfc.
void addColumn(const std::string &col_name, const std::string &version, const std::string &default_value="")
Adds metadata for a single column to the schema.
Implements a CSV file that supports multiple versions of the file&#39;s "schema".
static HWAddr fromText(const std::string &text, const uint16_t htype=HTYPE_ETHER)
Creates instance of the hardware address from textual format.
Definition: hwaddr.cc:70
size_t getColumnIndex(const std::string &col_name) const
Returns the index of the column having specified name.
Definition: csv_file.cc:237
std::string readAt(const size_t at) const
Retrieves a value from the internal container.
Definition: csv_file.cc:60
static std::string basicStatesToText(const uint32_t state)
Returns name(s) of the basic lease state(s).
Definition: lease.cc:90
Hardware type that represents information from DHCPv4 packet.
Definition: hwaddr.h:20
void append(const Lease4 &lease)
Appends the lease record to the CSV file.
isc::asiolink::IOAddress addr_
IPv4 ot IPv6 address.
Definition: lease.h:114
void writeAt(const size_t at, const char *value)
Replaces the value at specified index.
Definition: csv_file.cc:84
std::string readAtEscaped(const size_t at) const
Retrieves a value from the internal container, free of escaped characters.
Definition: csv_file.cc:66
static const uint32_t STATE_DECLINED
Declined lease.
Definition: lease.h:71
uint32_t read_leases_
Number of leases read.
virtual void open(const bool seek_to_end=false)
Opens a lease file.
uint32_t valid_lft_
Valid lifetime.
Definition: lease.h:119
uint32_t read_errs_
Number of errors when reading.
uint32_t SubnetID
Defines unique IPv4 or IPv6 subnet identifier.
Definition: subnet_id.h:24