Kea 2.2.0
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
11using namespace isc::asiolink;
12using namespace isc::data;
13using namespace isc::util;
14
15namespace isc {
16namespace dhcp {
17
18CSVLeaseFile4::CSVLeaseFile4(const std::string& filename)
19 : VersionedCSVFile(filename) {
20 initColumns();
21}
22
23void
24CSVLeaseFile4::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
32void
34 // Bump the number of write attempts
35 ++writes_;
36
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
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
79 throw;
80 }
81
82 // Bump the number of leases written
84}
85
86bool
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: "
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
166void
167CSVLeaseFile4::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
184CSVLeaseFile4::readAddress(const CSVRow& row) {
185 IOAddress address(row.readAt(getColumnIndex("address")));
186 return (address);
187}
188
189HWAddr
190CSVLeaseFile4::readHWAddr(const CSVRow& row) {
191 HWAddr hwaddr = HWAddr::fromText(row.readAt(getColumnIndex("hwaddr")));
192 return (hwaddr);
193}
194
196CSVLeaseFile4::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
206uint32_t
207CSVLeaseFile4::readValid(const CSVRow& row) {
208 uint32_t valid =
209 row.readAndConvertAt<uint32_t>(getColumnIndex("valid_lifetime"));
210 return (valid);
211}
212
213time_t
214CSVLeaseFile4::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
222CSVLeaseFile4::readSubnetID(const CSVRow& row) {
223 SubnetID subnet_id =
224 row.readAndConvertAt<SubnetID>(getColumnIndex("subnet_id"));
225 return (subnet_id);
226}
227
228bool
229CSVLeaseFile4::readFqdnFwd(const CSVRow& row) {
230 bool fqdn_fwd = row.readAndConvertAt<bool>(getColumnIndex("fqdn_fwd"));
231 return (fqdn_fwd);
232}
233
234bool
235CSVLeaseFile4::readFqdnRev(const CSVRow& row) {
236 bool fqdn_rev = row.readAndConvertAt<bool>(getColumnIndex("fqdn_rev"));
237 return (fqdn_rev);
238}
239
240std::string
241CSVLeaseFile4::readHostname(const CSVRow& row) {
242 std::string hostname = row.readAtEscaped(getColumnIndex("hostname"));
243 return (hostname);
244}
245
246uint32_t
247CSVLeaseFile4::readState(const util::CSVRow& row) {
248 uint32_t state = row.readAndConvertAt<uint32_t>(getColumnIndex("state"));
249 return (state);
250}
251
253CSVLeaseFile4::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
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
static ElementPtr fromJSON(const std::string &in, bool preproc=false)
These functions will parse the given string (JSON) representation of a compound element.
Definition: data.cc:764
void append(const Lease4 &lease)
Appends the lease record to the CSV file.
CSVLeaseFile4(const std::string &filename)
Constructor.
virtual void open(const bool seek_to_end=false)
Opens a lease file.
bool next(Lease4Ptr &lease)
Reads next lease from the CSV file.
static ClientIdPtr fromText(const std::string &text)
Create client identifier from the textual format.
Definition: duid.cc:132
uint32_t write_leases_
Number of lease written.
uint32_t read_leases_
Number of leases read.
uint32_t reads_
Number of attempts to read a lease.
void clearStatistics()
Clears the statistics.
uint32_t writes_
Number of attempts to write a lease.
uint32_t write_errs_
Number of errors when writing.
uint32_t read_errs_
Number of errors when reading.
size_t getColumnCount() const
Returns the number of columns in the file.
Definition: csv_file.h:403
void setReadMsg(const std::string &read_msg)
Sets error message after row validation.
Definition: csv_file.h:486
size_t getColumnIndex(const std::string &col_name) const
Returns the index of the column having specified name.
Definition: csv_file.cc:237
Represents a single row of the CSV file.
Definition: csv_file.h:51
T readAndConvertAt(const size_t at) const
Retrieves a value from the internal container.
Definition: csv_file.h:156
std::string readAtEscaped(const size_t at) const
Retrieves a value from the internal container, free of escaped characters.
Definition: csv_file.cc:66
void writeAt(const size_t at, const char *value)
Replaces the value at specified index.
Definition: csv_file.cc:84
std::string readAt(const size_t at) const
Retrieves a value from the internal container.
Definition: csv_file.cc:60
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
Implements a CSV file that supports multiple versions of the file's "schema".
void setMinimumValidColumns(const std::string &column_name)
Sets the minimum number of valid columns based on a given column.
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.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:27
boost::shared_ptr< HWAddr > HWAddrPtr
Shared pointer to a hardware address structure.
Definition: hwaddr.h:154
uint32_t SubnetID
Defines unique IPv4 or IPv6 subnet identifier.
Definition: subnet_id.h:24
boost::shared_ptr< ClientId > ClientIdPtr
Shared pointer to a Client ID.
Definition: duid.h:103
boost::shared_ptr< Lease4 > Lease4Ptr
Pointer to a Lease4 structure.
Definition: lease.h:284
Definition: edns.h:19
Defines the logger used by the top-level component of kea-lfc.
data::ConstElementPtr getContext() const
Returns const pointer to the user context.
Definition: user_context.h:24
Hardware type that represents information from DHCPv4 packet.
Definition: hwaddr.h:20
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
std::vector< uint8_t > hwaddr_
Definition: hwaddr.h:98
Structure that holds a lease for IPv4 address.
Definition: lease.h:295
ClientIdPtr client_id_
Client identifier.
Definition: lease.h:301
SubnetID subnet_id_
Subnet identifier.
Definition: lease.h:154
uint32_t valid_lft_
Valid lifetime.
Definition: lease.h:125
static std::string basicStatesToText(const uint32_t state)
Returns name(s) of the basic lease state(s).
Definition: lease.cc:90
static const uint32_t STATE_DECLINED
Declined lease.
Definition: lease.h:72
std::string hostname_
Client hostname.
Definition: lease.h:159
uint32_t state_
Holds the lease state(s).
Definition: lease.h:185
bool fqdn_fwd_
Forward zone updated?
Definition: lease.h:164
time_t cltt_
Client last transmission time.
Definition: lease.h:143
HWAddrPtr hwaddr_
Client's MAC/hardware address.
Definition: lease.h:174
bool fqdn_rev_
Reverse zone updated?
Definition: lease.h:169
isc::asiolink::IOAddress addr_
IPv4 ot IPv6 address.
Definition: lease.h:120