csv_lease_file4.cc 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. // Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <config.h>
  15. #include <dhcpsrv/csv_lease_file4.h>
  16. using namespace isc::asiolink;
  17. using namespace isc::util;
  18. namespace isc {
  19. namespace dhcp {
  20. CSVLeaseFile4::CSVLeaseFile4(const std::string& filename)
  21. : VersionedCSVFile(filename) {
  22. initColumns();
  23. }
  24. void
  25. CSVLeaseFile4::open(const bool seek_to_end) {
  26. // Call the base class to open the file
  27. VersionedCSVFile::open(seek_to_end);
  28. // and clear any statistics we may have
  29. clearStatistics();
  30. }
  31. void
  32. CSVLeaseFile4::append(const Lease4& lease) {
  33. // Bump the number of write attempts
  34. ++writes_;
  35. CSVRow row(getColumnCount());
  36. row.writeAt(getColumnIndex("address"), lease.addr_.toText());
  37. if (!lease.hwaddr_) {
  38. // Bump the error counter
  39. ++write_errs_;
  40. isc_throw(BadValue, "Lease4 must have hardware address specified.");
  41. }
  42. row.writeAt(getColumnIndex("hwaddr"), lease.hwaddr_->toText(false));
  43. // Client id may be unset (NULL).
  44. if (lease.client_id_) {
  45. row.writeAt(getColumnIndex("client_id"), lease.client_id_->toText());
  46. }
  47. row.writeAt(getColumnIndex("valid_lifetime"), lease.valid_lft_);
  48. row.writeAt(getColumnIndex("expire"), lease.cltt_ + lease.valid_lft_);
  49. row.writeAt(getColumnIndex("subnet_id"), lease.subnet_id_);
  50. row.writeAt(getColumnIndex("fqdn_fwd"), lease.fqdn_fwd_);
  51. row.writeAt(getColumnIndex("fqdn_rev"), lease.fqdn_rev_);
  52. row.writeAt(getColumnIndex("hostname"), lease.hostname_);
  53. row.writeAt(getColumnIndex("state"), lease.state_);
  54. try {
  55. VersionedCSVFile::append(row);
  56. } catch (const std::exception&) {
  57. // Catch any errors so we can bump the error counter than rethrow it
  58. ++write_errs_;
  59. throw;
  60. }
  61. // Bump the number of leases written
  62. ++write_leases_;
  63. }
  64. bool
  65. CSVLeaseFile4::next(Lease4Ptr& lease) {
  66. // Bump the number of read attempts
  67. ++reads_;
  68. // Read the CSV row and try to create a lease from the values read.
  69. // This may easily result in exception. We don't want this function
  70. // to throw exceptions, so we catch them all and rather return the
  71. // false value.
  72. try {
  73. // Get the row of CSV values.
  74. CSVRow row;
  75. VersionedCSVFile::next(row);
  76. // The empty row signals EOF.
  77. if (row == CSVFile::EMPTY_ROW()) {
  78. lease.reset();
  79. return (true);
  80. }
  81. // Get client id. It is possible that the client id is empty and the
  82. // returned pointer is NULL. This is ok, but if the client id is NULL,
  83. // we need to be careful to not use the NULL pointer.
  84. ClientIdPtr client_id = readClientId(row);
  85. std::vector<uint8_t> client_id_vec;
  86. if (client_id) {
  87. client_id_vec = client_id->getClientId();
  88. }
  89. size_t client_id_len = client_id_vec.size();
  90. // Get the HW address. It should never be empty and the readHWAddr checks
  91. // that.
  92. HWAddr hwaddr = readHWAddr(row);
  93. lease.reset(new Lease4(readAddress(row),
  94. HWAddrPtr(new HWAddr(hwaddr)),
  95. client_id_vec.empty() ? NULL : &client_id_vec[0],
  96. client_id_len,
  97. readValid(row),
  98. 0, 0, // t1, t2 = 0
  99. readCltt(row),
  100. readSubnetID(row),
  101. readFqdnFwd(row),
  102. readFqdnRev(row),
  103. readHostname(row)));
  104. lease->state_ = readState(row);
  105. } catch (std::exception& ex) {
  106. // bump the read error count
  107. ++read_errs_;
  108. // The lease might have been created, so let's set it back to NULL to
  109. // signal that lease hasn't been parsed.
  110. lease.reset();
  111. setReadMsg(ex.what());
  112. return (false);
  113. }
  114. // bump the number of leases read
  115. ++read_leases_;
  116. return (true);
  117. }
  118. void
  119. CSVLeaseFile4::initColumns() {
  120. addColumn("address", "1.0");
  121. addColumn("hwaddr", "1.0");
  122. addColumn("client_id", "1.0");
  123. addColumn("valid_lifetime", "1.0");
  124. addColumn("expire", "1.0");
  125. addColumn("subnet_id", "1.0");
  126. addColumn("fqdn_fwd", "1.0");
  127. addColumn("fqdn_rev", "1.0");
  128. addColumn("hostname", "1.0");
  129. addColumn("state", "2.0", "0");
  130. // Any file with less than hostname is invalid
  131. setMinimumValidColumns("hostname");
  132. }
  133. IOAddress
  134. CSVLeaseFile4::readAddress(const CSVRow& row) {
  135. IOAddress address(row.readAt(getColumnIndex("address")));
  136. return (address);
  137. }
  138. HWAddr
  139. CSVLeaseFile4::readHWAddr(const CSVRow& row) {
  140. HWAddr hwaddr = HWAddr::fromText(row.readAt(getColumnIndex("hwaddr")));
  141. if (hwaddr.hwaddr_.empty()) {
  142. isc_throw(isc::BadValue, "hardware address in the lease file"
  143. " must not be empty");
  144. }
  145. return (hwaddr);
  146. }
  147. ClientIdPtr
  148. CSVLeaseFile4::readClientId(const CSVRow& row) {
  149. std::string client_id = row.readAt(getColumnIndex("client_id"));
  150. // NULL client ids are allowed in DHCPv4.
  151. if (client_id.empty()) {
  152. return (ClientIdPtr());
  153. }
  154. ClientIdPtr cid = ClientId::fromText(client_id);
  155. return (cid);
  156. }
  157. uint32_t
  158. CSVLeaseFile4::readValid(const CSVRow& row) {
  159. uint32_t valid =
  160. row.readAndConvertAt<uint32_t>(getColumnIndex("valid_lifetime"));
  161. return (valid);
  162. }
  163. time_t
  164. CSVLeaseFile4::readCltt(const CSVRow& row) {
  165. uint32_t cltt = row.readAndConvertAt<uint32_t>(getColumnIndex("expire"))
  166. - readValid(row);
  167. return (cltt);
  168. }
  169. SubnetID
  170. CSVLeaseFile4::readSubnetID(const CSVRow& row) {
  171. SubnetID subnet_id =
  172. row.readAndConvertAt<SubnetID>(getColumnIndex("subnet_id"));
  173. return (subnet_id);
  174. }
  175. bool
  176. CSVLeaseFile4::readFqdnFwd(const CSVRow& row) {
  177. bool fqdn_fwd = row.readAndConvertAt<bool>(getColumnIndex("fqdn_fwd"));
  178. return (fqdn_fwd);
  179. }
  180. bool
  181. CSVLeaseFile4::readFqdnRev(const CSVRow& row) {
  182. bool fqdn_rev = row.readAndConvertAt<bool>(getColumnIndex("fqdn_rev"));
  183. return (fqdn_rev);
  184. }
  185. std::string
  186. CSVLeaseFile4::readHostname(const CSVRow& row) {
  187. std::string hostname = row.readAt(getColumnIndex("hostname"));
  188. return (hostname);
  189. }
  190. uint32_t
  191. CSVLeaseFile4::readState(const util::CSVRow& row) {
  192. uint32_t state = row.readAndConvertAt<uint32_t>(getColumnIndex("state"));
  193. return (state);
  194. }
  195. } // end of namespace isc::dhcp
  196. } // end of namespace isc