cql_lease_mgr.cc 71 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971
  1. // Copyright (C) 2015 - 2016 Deutsche Telekom AG.
  2. //
  3. // Author: Razvan Becheriu <razvan.becheriu@qualitance.com>
  4. //
  5. // Licensed under the Apache License, Version 2.0 (the "License");
  6. // you may not use this file except in compliance with the License.
  7. // You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing, software
  12. // distributed under the License is distributed on an "AS IS" BASIS,
  13. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. // See the License for the specific language governing permissions and
  15. // limitations under the License.
  16. #include <config.h>
  17. #include <asiolink/io_address.h>
  18. #include <dhcp/duid.h>
  19. #include <dhcp/hwaddr.h>
  20. #include <dhcpsrv/dhcpsrv_log.h>
  21. #include <dhcpsrv/cql_lease_mgr.h>
  22. #include <boost/static_assert.hpp>
  23. #include <iostream>
  24. #include <iomanip>
  25. #include <sstream>
  26. #include <string>
  27. #include <ctime>
  28. using namespace isc;
  29. using namespace isc::dhcp;
  30. using namespace std;
  31. namespace isc {
  32. namespace dhcp {
  33. static const size_t HOSTNAME_MAX_LEN = 255U;
  34. static const size_t ADDRESS6_TEXT_MAX_LEN = 39U;
  35. /// @name CqlBind auxiliary methods for binding data into Cassandra format:
  36. /// @{
  37. /// @todo These void* cast are unsafe. See ticket #4525.
  38. static CassError CqlBindNone(CassStatement* statement, size_t index, void*) {
  39. return cass_statement_bind_null(statement, index);
  40. }
  41. static CassError CqlBindBool(CassStatement* statement, size_t index,
  42. void* value) {
  43. return cass_statement_bind_bool(statement, index,
  44. *(static_cast<cass_bool_t*>(value)));
  45. }
  46. static CassError CqlBindInt32(CassStatement* statement, size_t index,
  47. void* value) {
  48. return cass_statement_bind_int32(statement, index,
  49. *(static_cast<cass_int32_t*>(value)));
  50. }
  51. static CassError CqlBindInt64(CassStatement* statement, size_t index,
  52. void* value) {
  53. return cass_statement_bind_int64(statement, index,
  54. *(static_cast<cass_int64_t*>(value)));
  55. }
  56. static CassError CqlBindTimestamp(CassStatement* statement, size_t index,
  57. void* value) {
  58. return cass_statement_bind_int64(statement, index,
  59. *(static_cast<cass_int64_t*>(value)));
  60. }
  61. static CassError CqlBindString(CassStatement* statement, size_t index,
  62. void* value) {
  63. return cass_statement_bind_string(statement, index,
  64. (static_cast<const char*>(value)));
  65. }
  66. static CassError CqlBindBytes(CassStatement* statement, size_t index,
  67. void* value) {
  68. return cass_statement_bind_bytes(statement, index,
  69. static_cast<std::vector<cass_byte_t>*>(value)->data(),
  70. static_cast<std::vector<cass_byte_t>*>(value)->size());
  71. }
  72. /// @}
  73. static CassError CqlGetNone(const CassValue*, void*, size_t*) {
  74. return CASS_OK;
  75. }
  76. static CassError CqlGetBool(const CassValue* value, void* data, size_t*) {
  77. return cass_value_get_bool(value, static_cast<cass_bool_t*>(data));
  78. }
  79. static CassError CqlGetInt32(const CassValue* value, void* data, size_t*) {
  80. return cass_value_get_int32(value, static_cast<cass_int32_t*>(data));
  81. }
  82. static CassError CqlGetInt64(const CassValue* value, void* data, size_t*) {
  83. return cass_value_get_int64(value, static_cast<cass_int64_t*>(data));
  84. }
  85. static CassError CqlGetTimestamp(const CassValue* value, void* data, size_t*) {
  86. return cass_value_get_int64(value, static_cast<cass_int64_t*>(data));
  87. }
  88. static CassError CqlGetString(const CassValue* value, void* data,
  89. size_t* size) {
  90. return cass_value_get_string(value, static_cast<const char**>(data), size);
  91. }
  92. static CassError CqlGetBytes(const CassValue* value, void* data, size_t* size) {
  93. return cass_value_get_bytes(value, static_cast<const cass_byte_t**>(data),
  94. size);
  95. }
  96. typedef CassError (*CqlBindFunction)(CassStatement* statement, size_t index,
  97. void* value);
  98. typedef CassError (*CqlGetFunction)(const CassValue* value, void* data,
  99. size_t* size);
  100. struct CqlFunctionData {
  101. CqlBindFunction sqlBindFunction_;
  102. CqlGetFunction sqlGetFunction_;
  103. };
  104. static struct CqlFunctionData CqlFunctions[] = {
  105. {CqlBindNone, CqlGetNone},
  106. {CqlBindBool, CqlGetBool},
  107. {CqlBindInt32, CqlGetInt32},
  108. {CqlBindInt64, CqlGetInt64},
  109. {CqlBindTimestamp, CqlGetTimestamp},
  110. {CqlBindString, CqlGetString},
  111. {CqlBindBytes, CqlGetBytes}
  112. };
  113. /// @brief Catalog of all the SQL statements currently supported. Note
  114. /// that the order columns appear in statement body must match the order they
  115. /// that the occur in the table. This does not apply to the where clause.
  116. static const char* delete_lease4_params[] = {
  117. static_cast<const char*>("address"),
  118. NULL };
  119. static const char* delete_expired_lease4_params[] = {
  120. static_cast<const char*>("state"),
  121. static_cast<const char*>("expire"),
  122. NULL };
  123. static const char* delete_lease6_params[] = {
  124. static_cast<const char*>("address"),
  125. NULL };
  126. static const char* delete_expired_lease6_params[] = {
  127. static_cast<const char*>("state"),
  128. static_cast<const char*>("expire"),
  129. NULL };
  130. static const char* get_lease4_addr_params[] = {
  131. static_cast<const char*>("address"),
  132. NULL };
  133. static const char* get_lease4_clientid_params[] = {
  134. static_cast<const char*>("client_id"),
  135. NULL };
  136. static const char* get_lease4_clientid_subid_params[] = {
  137. static_cast<const char*>("client_id"),
  138. static_cast<const char*>("subnet_id"),
  139. NULL };
  140. static const char* get_lease4_hwaddr_params[] = {
  141. static_cast<const char*>("hwaddr"),
  142. NULL };
  143. static const char* get_lease4_hwaddr_subid_params[] = {
  144. static_cast<const char*>("hwaddr"),
  145. static_cast<const char*>("subnet_id"),
  146. NULL };
  147. static const char* get_lease4_expired_params[] = {
  148. static_cast<const char*>("state"),
  149. static_cast<const char*>("expire"),
  150. static_cast<const char*>("limit"),
  151. NULL };
  152. static const char* get_lease6_addr_params[] = {
  153. static_cast<const char*>("address"),
  154. static_cast<const char*>("lease_type"),
  155. NULL };
  156. static const char* get_lease6_duid_iaid_params[] = {
  157. static_cast<const char*>("duid"),
  158. static_cast<const char*>("iaid"),
  159. static_cast<const char*>("lease_type"),
  160. NULL };
  161. static const char* get_lease6_duid_iaid_subid_params[] = {
  162. static_cast<const char*>("duid"),
  163. static_cast<const char*>("iaid"),
  164. static_cast<const char*>("subnet_id"),
  165. static_cast<const char*>("lease_type"),
  166. NULL };
  167. static const char* get_lease6_expired_params[] = {
  168. static_cast<const char*>("state"),
  169. static_cast<const char*>("expire"),
  170. static_cast<const char*>("limit"),
  171. NULL };
  172. static const char* get_version_params[] = {
  173. NULL };
  174. static const char* insert_lease4_params[] = {
  175. static_cast<const char*>("address"),
  176. static_cast<const char*>("hwaddr"),
  177. static_cast<const char*>("client_id"),
  178. static_cast<const char*>("valid_lifetime"),
  179. static_cast<const char*>("expire"),
  180. static_cast<const char*>("subnet_id"),
  181. static_cast<const char*>("fqdn_fwd"),
  182. static_cast<const char*>("fqdn_rev"),
  183. static_cast<const char*>("hostname"),
  184. static_cast<const char*>("state"),
  185. NULL };
  186. static const char* insert_lease6_params[] = {
  187. static_cast<const char*>("address"),
  188. static_cast<const char*>("duid"),
  189. static_cast<const char*>("valid_lifetime"),
  190. static_cast<const char*>("expire"),
  191. static_cast<const char*>("subnet_id"),
  192. static_cast<const char*>("pref_lifetime"),
  193. static_cast<const char*>("lease_type"),
  194. static_cast<const char*>("iaid"),
  195. static_cast<const char*>("prefix_len"),
  196. static_cast<const char*>("fqdn_fwd"),
  197. static_cast<const char*>("fqdn_rev"),
  198. static_cast<const char*>("hostname"),
  199. static_cast<const char*>("hwaddr"),
  200. static_cast<const char*>("hwtype"),
  201. static_cast<const char*>("hwaddr_source"),
  202. static_cast<const char*>("state"),
  203. NULL };
  204. static const char* update_lease4_params[] = {
  205. static_cast<const char*>("hwaddr"),
  206. static_cast<const char*>("client_id"),
  207. static_cast<const char*>("valid_lifetime"),
  208. static_cast<const char*>("expire"),
  209. static_cast<const char*>("subnet_id"),
  210. static_cast<const char*>("fqdn_fwd"),
  211. static_cast<const char*>("fqdn_rev"),
  212. static_cast<const char*>("hostname"),
  213. static_cast<const char*>("state"),
  214. static_cast<const char*>("address"),
  215. NULL };
  216. static const char* update_lease6_params[] = {
  217. static_cast<const char*>("duid"),
  218. static_cast<const char*>("valid_lifetime"),
  219. static_cast<const char*>("expire"),
  220. static_cast<const char*>("subnet_id"),
  221. static_cast<const char*>("pref_lifetime"),
  222. static_cast<const char*>("lease_type"),
  223. static_cast<const char*>("iaid"),
  224. static_cast<const char*>("prefix_len"),
  225. static_cast<const char*>("fqdn_fwd"),
  226. static_cast<const char*>("fqdn_rev"),
  227. static_cast<const char*>("hostname"),
  228. static_cast<const char*>("hwaddr"),
  229. static_cast<const char*>("hwtype"),
  230. static_cast<const char*>("hwaddr_source"),
  231. static_cast<const char*>("state"),
  232. static_cast<const char*>("address"),
  233. NULL };
  234. CqlTaggedStatement CqlLeaseMgr::tagged_statements_[] = {
  235. // DELETE_LEASE4
  236. { delete_lease4_params,
  237. "delete_lease4",
  238. "DELETE FROM lease4 WHERE address = ? "
  239. "IF EXISTS" },
  240. // DELETE_LEASE4_STATE_EXPIRED
  241. { delete_expired_lease4_params,
  242. "delete_lease4_expired",
  243. "SELECT address, hwaddr, client_id, "
  244. "valid_lifetime, expire, subnet_id, "
  245. "fqdn_fwd, fqdn_rev, hostname, state "
  246. "FROM lease4 "
  247. "WHERE state = ? AND expire < ? "
  248. "ALLOW FILTERING" },
  249. // DELETE_LEASE6
  250. { delete_lease6_params,
  251. "delete_lease6",
  252. "DELETE FROM lease6 WHERE address = ? "
  253. "IF EXISTS" },
  254. // DELETE_LEASE6_STATE_EXPIRED
  255. { delete_expired_lease6_params,
  256. "delete_lease6_expired",
  257. "SELECT address, duid, valid_lifetime, "
  258. "expire, subnet_id, pref_lifetime, "
  259. "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
  260. "hwaddr, hwtype, hwaddr_source, state "
  261. "FROM lease6 "
  262. "WHERE state = ? AND expire < ? "
  263. "ALLOW FILTERING" },
  264. // GET_LEASE4_ADDR
  265. { get_lease4_addr_params,
  266. "get_lease4_addr",
  267. "SELECT address, hwaddr, client_id, "
  268. "valid_lifetime, expire, subnet_id, "
  269. "fqdn_fwd, fqdn_rev, hostname, state "
  270. "FROM lease4 "
  271. "WHERE address = ?" },
  272. // GET_LEASE4_CLIENTID
  273. { get_lease4_clientid_params,
  274. "get_lease4_clientid",
  275. "SELECT address, hwaddr, client_id, "
  276. "valid_lifetime, expire, subnet_id, "
  277. "fqdn_fwd, fqdn_rev, hostname, state "
  278. "FROM lease4 "
  279. "WHERE client_id = ?" },
  280. // GET_LEASE4_CLIENTID_SUBID
  281. { get_lease4_clientid_subid_params,
  282. "get_lease4_clientid_subid",
  283. "SELECT address, hwaddr, client_id, "
  284. "valid_lifetime, expire, subnet_id, "
  285. "fqdn_fwd, fqdn_rev, hostname, state "
  286. "FROM lease4 "
  287. "WHERE client_id = ? AND subnet_id = ? "
  288. "ALLOW FILTERING" },
  289. // GET_LEASE4_HWADDR
  290. { get_lease4_hwaddr_params,
  291. "get_lease4_hwaddr",
  292. "SELECT address, hwaddr, client_id, "
  293. "valid_lifetime, expire, subnet_id, "
  294. "fqdn_fwd, fqdn_rev, hostname, state "
  295. "FROM lease4 "
  296. "WHERE hwaddr = ?" },
  297. // GET_LEASE4_HWADDR_SUBID
  298. { get_lease4_hwaddr_subid_params,
  299. "get_lease4_hwaddr_subid",
  300. "SELECT address, hwaddr, client_id, "
  301. "valid_lifetime, expire, subnet_id, "
  302. "fqdn_fwd, fqdn_rev, hostname, state "
  303. "FROM lease4 "
  304. "WHERE hwaddr = ? AND subnet_id = ? "
  305. "ALLOW FILTERING" },
  306. // GET_LEASE4_EXPIRE
  307. { get_lease4_expired_params,
  308. "get_lease4_expired",
  309. "SELECT address, hwaddr, client_id, "
  310. "valid_lifetime, expire, subnet_id, "
  311. "fqdn_fwd, fqdn_rev, hostname, state "
  312. "FROM lease4 "
  313. "WHERE state = ? AND expire < ? "
  314. "LIMIT ? "
  315. "ALLOW FILTERING" },
  316. // GET_LEASE6_ADDR
  317. { get_lease6_addr_params,
  318. "get_lease6_addr",
  319. "SELECT address, duid, valid_lifetime, "
  320. "expire, subnet_id, pref_lifetime, "
  321. "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
  322. "hwaddr, hwtype, hwaddr_source, state "
  323. "FROM lease6 "
  324. "WHERE address = ? AND lease_type = ? "
  325. "ALLOW FILTERING" },
  326. // GET_LEASE6_DUID_IAID
  327. { get_lease6_duid_iaid_params,
  328. "get_lease6_duid_iaid",
  329. "SELECT address, duid, valid_lifetime, "
  330. "expire, subnet_id, pref_lifetime, "
  331. "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
  332. "hwaddr, hwtype, hwaddr_source, state "
  333. "FROM lease6 "
  334. "WHERE duid = ? AND iaid = ? AND lease_type = ? "
  335. "ALLOW FILTERING" },
  336. // GET_LEASE6_DUID_IAID_SUBID
  337. { get_lease6_duid_iaid_subid_params,
  338. "get_lease6_duid_iaid_subid",
  339. "SELECT address, duid, valid_lifetime, "
  340. "expire, subnet_id, pref_lifetime, "
  341. "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
  342. "hwaddr, hwtype, hwaddr_source, state "
  343. "FROM lease6 "
  344. "WHERE duid = ? AND iaid = ? AND subnet_id = ? AND lease_type = ? "
  345. "ALLOW FILTERING" },
  346. // GET_LEASE6_EXPIRE
  347. { get_lease6_expired_params,
  348. "get_lease6_expired",
  349. "SELECT address, duid, valid_lifetime, "
  350. "expire, subnet_id, pref_lifetime, "
  351. "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
  352. "hwaddr, hwtype, hwaddr_source, state "
  353. "FROM lease6 "
  354. "WHERE state = ? AND expire < ? "
  355. "LIMIT ? "
  356. "ALLOW FILTERING" },
  357. // GET_VERSION
  358. { get_version_params,
  359. "get_version",
  360. "SELECT version, minor FROM schema_version" },
  361. // INSERT_LEASE4
  362. { insert_lease4_params,
  363. "insert_lease4",
  364. "INSERT INTO lease4(address, hwaddr, client_id, "
  365. "valid_lifetime, expire, subnet_id, fqdn_fwd, fqdn_rev, hostname, "
  366. "state) "
  367. "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) "
  368. "IF NOT EXISTS" },
  369. // INSERT_LEASE6
  370. { insert_lease6_params,
  371. "insert_lease6",
  372. "INSERT INTO lease6(address, duid, valid_lifetime, "
  373. "expire, subnet_id, pref_lifetime, "
  374. "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, hwaddr, "
  375. "hwtype, hwaddr_source, state) "
  376. "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) "
  377. "IF NOT EXISTS" },
  378. // UPDATE_LEASE4
  379. { update_lease4_params,
  380. "update_lease4",
  381. "UPDATE lease4 SET hwaddr = ?, "
  382. "client_id = ?, valid_lifetime = ?, expire = ?, "
  383. "subnet_id = ?, fqdn_fwd = ?, fqdn_rev = ?, hostname = ?, state = ? "
  384. "WHERE address = ? "
  385. "IF EXISTS" },
  386. // UPDATE_LEASE6
  387. { update_lease6_params,
  388. "update_lease6",
  389. "UPDATE lease6 SET duid = ?, "
  390. "valid_lifetime = ?, expire = ?, subnet_id = ?, "
  391. "pref_lifetime = ?, lease_type = ?, iaid = ?, "
  392. "prefix_len = ?, fqdn_fwd = ?, fqdn_rev = ?, hostname = ?, "
  393. "hwaddr = ?, hwtype = ?, hwaddr_source = ?, state = ? "
  394. "WHERE address = ? "
  395. "IF EXISTS" },
  396. // End of list sentinel
  397. { NULL, NULL, NULL }
  398. };
  399. /// @brief Common CQL and Lease Data Methods
  400. ///
  401. /// The CqlLease4Exchange and CqlLease6Exchange classes provide the
  402. /// functionality to set up binding information between variables in the
  403. /// program and data extracted from the database. This class is the common
  404. /// base to both of them, containing some common methods.
  405. class CqlLeaseExchange : public CqlExchange {
  406. public:
  407. CqlLeaseExchange() : hwaddr_length_(0), expire_(0), subnet_id_(0),
  408. valid_lifetime_(0), fqdn_fwd_(false), fqdn_rev_(false),
  409. hostname_length_(0), state_(0) {
  410. memset(hwaddr_buffer_, 0, sizeof(hwaddr_buffer_));
  411. memset(hostname_buffer_, 0, sizeof(hostname_buffer_));
  412. }
  413. protected:
  414. std::vector<uint8_t> hwaddr_; ///< Hardware address
  415. uint8_t hwaddr_buffer_[HWAddr::MAX_HWADDR_LEN];
  416. ///< Hardware address buffer
  417. unsigned long hwaddr_length_; ///< Hardware address length
  418. uint64_t expire_; ///< Lease expiry time
  419. uint32_t subnet_id_; ///< Subnet identification
  420. uint64_t valid_lifetime_; ///< Lease time
  421. uint32_t fqdn_fwd_; ///< Has forward DNS update been
  422. ///< performed
  423. uint32_t fqdn_rev_; ///< Has reverse DNS update been
  424. ///< performed
  425. char hostname_buffer_[HOSTNAME_MAX_LEN + 1];
  426. ///< Client hostname
  427. unsigned long hostname_length_; ///< Client hostname length
  428. uint32_t state_; ///< Lease state
  429. };
  430. class CqlVersionExchange : public virtual CqlExchange {
  431. public:
  432. /// @brief Constructor
  433. ///
  434. /// The initialization of the variables here is only to satisfy cppcheck -
  435. /// all variables are initialized/set in the methods before they are used.
  436. CqlVersionExchange() {
  437. const size_t MAX_COLUMNS = 2U;
  438. // Set the column names
  439. size_t offset = 0U;
  440. BOOST_STATIC_ASSERT(2U == MAX_COLUMNS);
  441. parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("version",
  442. offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_INT32)));
  443. parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("minor",
  444. offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_INT32)));
  445. BOOST_ASSERT(parameters_.size() == MAX_COLUMNS);
  446. }
  447. };
  448. /// @brief Exchange CQL and Lease4 Data
  449. ///
  450. /// On any CQL operation, arrays of CQL BIND structures must be built to
  451. /// describe the parameters in the prepared statements. Where information is
  452. /// inserted or retrieved - INSERT, UPDATE, SELECT - a large amount of that
  453. /// structure is identical. This class handles the creation of that array.
  454. ///
  455. /// Owing to the CQL API, the process requires some intermediate variables
  456. /// to hold things like data length etc. This object holds those variables.
  457. ///
  458. /// @note There are no unit tests for this class. It is tested indirectly
  459. /// in all CqlLeaseMgr::xxx4() calls where it is used.
  460. class CqlLease4Exchange : public CqlLeaseExchange {
  461. public:
  462. /// @brief Constructor
  463. ///
  464. /// The initialization of the variables here is only to satisfy cppcheck -
  465. /// all variables are initialized/set in the methods before they are used.
  466. CqlLease4Exchange() : addr4_(0), client_id_length_(0),
  467. client_id_null_(false) {
  468. const size_t MAX_COLUMNS = 12U;
  469. memset(client_id_buffer_, 0, sizeof(client_id_buffer_));
  470. // Set the column names
  471. size_t offset = 0U;
  472. BOOST_STATIC_ASSERT(12U == MAX_COLUMNS);
  473. parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("address",
  474. offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_INT32)));
  475. parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("hwaddr",
  476. offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_BYTES)));
  477. parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("client_id",
  478. offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_BYTES)));
  479. parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("valid_lifetime",
  480. offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_INT64)));
  481. parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("expire",
  482. offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_TIMESTAMP)));
  483. parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("subnet_id",
  484. offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_INT32)));
  485. parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("fqdn_fwd",
  486. offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_BOOL)));
  487. parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("fqdn_rev",
  488. offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_BOOL)));
  489. parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("hostname",
  490. offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_STRING)));
  491. parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("state",
  492. offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_INT32)));
  493. parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("limit",
  494. offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_INT32)));
  495. parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("[applied]",
  496. offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_BOOL)));
  497. BOOST_ASSERT(parameters_.size() == MAX_COLUMNS);
  498. }
  499. /// @brief Create CQL_BIND objects for Lease4 Pointer
  500. ///
  501. /// Fills in the CQL_BIND array for sending data in the Lease4 object to
  502. /// the database.
  503. void createBindForSend(const Lease4Ptr& lease, CqlDataArray& data) {
  504. if (!lease) {
  505. isc_throw(BadValue, "createBindForSend:: Lease4 object is NULL");
  506. }
  507. // Store lease object to ensure it remains valid.
  508. lease_ = lease;
  509. // Set up the structures for the various components of the lease4
  510. // structure.
  511. try {
  512. // address: int
  513. // The address in the Lease structure is an IOAddress object.
  514. // Convert this to an integer for storage.
  515. addr4_ = lease_->addr_.toUint32();
  516. data.add(&addr4_);
  517. // hwaddr: blob
  518. HWAddrPtr hwaddr = lease_->hwaddr_;
  519. if (hwaddr) {
  520. if (hwaddr->hwaddr_.size() > HWAddr::MAX_HWADDR_LEN) {
  521. isc_throw(DbOperationError, "Hardware address length " <<
  522. lease_->hwaddr_->hwaddr_.size() <<
  523. " exceeds maximum allowed of " <<
  524. HWAddr::MAX_HWADDR_LEN);
  525. }
  526. hwaddr_ = hwaddr->hwaddr_;
  527. } else {
  528. hwaddr_.clear();
  529. }
  530. hwaddr_length_ = hwaddr_.size();
  531. data.add(&hwaddr_);
  532. // client_id: blob
  533. if (lease_->client_id_) {
  534. client_id_ = lease_->client_id_->getClientId();
  535. } else {
  536. client_id_.clear();
  537. }
  538. client_id_length_ = client_id_.size();
  539. data.add(&client_id_);
  540. // valid lifetime: bigint
  541. valid_lifetime_ = lease_->valid_lft_;
  542. data.add(&valid_lifetime_);
  543. // expire: bigint
  544. // The lease structure holds the client last transmission time (cltt_)
  545. // For convenience for external tools, this is converted to lease
  546. // expiry time (expire). The relationship is given by:
  547. //
  548. // expire = cltt_ + valid_lft_
  549. CqlLeaseExchange::convertToDatabaseTime(lease_->cltt_,
  550. lease_->valid_lft_, expire_);
  551. data.add(&expire_);
  552. // subnet_id: int
  553. // Can use lease_->subnet_id_ directly as it is of type uint32_t.
  554. subnet_id_ = lease_->subnet_id_;
  555. data.add(&subnet_id_);
  556. // fqdn_fwd: boolean
  557. fqdn_fwd_ = lease_->fqdn_fwd_;
  558. data.add(&fqdn_fwd_);
  559. // fqdn_rev: boolean
  560. fqdn_rev_ = lease_->fqdn_rev_;
  561. data.add(&fqdn_rev_);
  562. // hostname: varchar
  563. hostname_length_ = lease_->hostname_.length();
  564. if (hostname_length_ >= sizeof(hostname_buffer_)) {
  565. isc_throw(BadValue, "hostname value is too large: " <<
  566. lease_->hostname_.c_str());
  567. }
  568. if (hostname_length_) {
  569. memcpy(hostname_buffer_, lease_->hostname_.c_str(),
  570. hostname_length_);
  571. }
  572. hostname_buffer_[hostname_length_] = '\0';
  573. data.add(hostname_buffer_);
  574. // state: int
  575. state_ = lease_->state_;
  576. data.add(&state_);
  577. } catch (const std::exception& ex) {
  578. isc_throw(DbOperationError,
  579. "Could not create bind array from Lease4: "
  580. << lease_->addr_.toText() << ", reason: " << ex.what());
  581. }
  582. }
  583. /// @brief Create BIND array to receive data
  584. ///
  585. /// Creates a CQL_BIND array to receive Lease4 data from the database.
  586. Lease4Ptr createBindForReceive(const CassRow* row) {
  587. try {
  588. unsigned char* hwaddr_buffer = NULL;
  589. const char* client_id_buffer = NULL;
  590. const char* hostname_buffer = NULL;
  591. CqlDataArray data;
  592. CqlDataArray size;
  593. // address: int
  594. data.add(reinterpret_cast<void*>(&addr4_));
  595. size.add(NULL);
  596. // hwaddr: blob
  597. data.add(reinterpret_cast<void*>(&hwaddr_buffer));
  598. size.add(reinterpret_cast<void*>(&hwaddr_length_));
  599. // client_id: blob
  600. data.add(reinterpret_cast<void*>(&client_id_buffer));
  601. size.add(reinterpret_cast<void*>(&client_id_length_));
  602. // valid_lifetime: bigint
  603. data.add(reinterpret_cast<void*>(&valid_lifetime_));
  604. size.add(NULL);
  605. // expire: bigint
  606. data.add(reinterpret_cast<void*>(&expire_));
  607. size.add(NULL);
  608. // subnet_id: int
  609. data.add(reinterpret_cast<void*>(&subnet_id_));
  610. size.add(NULL);
  611. // fqdn_fwd: boolean
  612. data.add(reinterpret_cast<void*>(&fqdn_fwd_));
  613. size.add(NULL);
  614. // fqdn_rev: boolean
  615. data.add(reinterpret_cast<void*>(&fqdn_rev_));
  616. size.add(NULL);
  617. // hostname: varchar
  618. data.add(reinterpret_cast<void*>(&hostname_buffer));
  619. size.add(reinterpret_cast<void*>(&hostname_length_));
  620. // state: int
  621. data.add(reinterpret_cast<void*>(&state_));
  622. size.add(NULL);
  623. for (size_t i = 0; i < data.size(); i++) {
  624. CqlLeaseMgr::getData(row, i, data, size, i, *this);
  625. }
  626. // hwaddr: blob
  627. hwaddr_.assign(hwaddr_buffer, hwaddr_buffer + hwaddr_length_);
  628. // client_id: blob
  629. client_id_.assign(client_id_buffer, client_id_buffer +
  630. client_id_length_);
  631. if (client_id_length_ >= sizeof(client_id_buffer_)) {
  632. isc_throw(BadValue, "client id value is too large: " <<
  633. client_id_buffer);
  634. }
  635. if (client_id_length_) {
  636. memcpy(client_id_buffer_, client_id_buffer, client_id_length_);
  637. }
  638. client_id_buffer_[client_id_length_] = '\0';
  639. // hostname: varchar
  640. if (hostname_length_ >= sizeof(hostname_buffer_)) {
  641. isc_throw(BadValue, "hostname value is too large: " <<
  642. hostname_buffer);
  643. }
  644. if (hostname_length_) {
  645. memcpy(hostname_buffer_, hostname_buffer, hostname_length_);
  646. }
  647. hostname_buffer_[hostname_length_] = '\0';
  648. time_t cltt = 0;
  649. CqlLeaseExchange::convertFromDatabaseTime(expire_, valid_lifetime_,
  650. cltt);
  651. // Recreate the hardware address.
  652. HWAddrPtr hwaddr(new HWAddr(hwaddr_, HTYPE_ETHER));
  653. std::string hostname(hostname_buffer_,
  654. hostname_buffer_ + hostname_length_);
  655. Lease4Ptr result(new Lease4(addr4_, hwaddr, client_id_buffer_,
  656. client_id_length_, valid_lifetime_, 0,
  657. 0, cltt, subnet_id_, fqdn_fwd_,
  658. fqdn_rev_, hostname));
  659. result->state_ = state_;
  660. return (result);
  661. } catch (const std::exception& ex) {
  662. isc_throw(DbOperationError,
  663. "Could not convert data to Lease4, reason: "
  664. << ex.what());
  665. }
  666. return (Lease4Ptr());
  667. }
  668. private:
  669. Lease4Ptr lease_; ///< Pointer to lease object
  670. uint32_t addr4_; ///< IPv4 address
  671. std::vector<uint8_t> client_id_; ///< Client identification
  672. uint8_t client_id_buffer_[ClientId::MAX_CLIENT_ID_LEN];
  673. ///< Client ID buffer
  674. unsigned long client_id_length_; ///< Client ID address length
  675. bool client_id_null_; ///< Is Client ID null?
  676. };
  677. /// @brief Exchange CQL and Lease6 Data
  678. ///
  679. /// On any CQL operation, arrays of CQL BIND structures must be built to
  680. /// describe the parameters in the prepared statements. Where information is
  681. /// inserted or retrieved - INSERT, UPDATE, SELECT - a large amount of that
  682. /// structure is identical. This class handles the creation of that array.
  683. ///
  684. /// Owing to the CQL API, the process requires some intermediate variables
  685. /// to hold things like data length etc. This object holds those variables.
  686. ///
  687. /// @note There are no unit tests for this class. It is tested indirectly
  688. /// in all CqlLeaseMgr::xxx6() calls where it is used.
  689. class CqlLease6Exchange : public CqlLeaseExchange {
  690. public:
  691. /// @brief Constructor
  692. ///
  693. /// The initialization of the variables here is nonly to satisfy cppcheck -
  694. /// all variables are initialized/set in the methods before they are used.
  695. CqlLease6Exchange() : addr6_length_(0), duid_length_(0), iaid_(0),
  696. lease_type_(0), prefixlen_(0), pref_lifetime_(0),
  697. hwaddr_null_(false), hwtype_(0), hwaddr_source_(0) {
  698. const size_t MAX_COLUMNS = 18U;
  699. memset(addr6_buffer_, 0, sizeof(addr6_buffer_));
  700. memset(duid_buffer_, 0, sizeof(duid_buffer_));
  701. // Set the column names
  702. size_t offset = 0U;
  703. BOOST_STATIC_ASSERT(18U == MAX_COLUMNS);
  704. parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("address",
  705. offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_STRING)));
  706. parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("duid",
  707. offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_BYTES)));
  708. parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("valid_lifetime",
  709. offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_INT64)));
  710. parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("expire",
  711. offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_TIMESTAMP)));
  712. parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("subnet_id",
  713. offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_INT32)));
  714. parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("pref_lifetime",
  715. offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_INT64)));
  716. parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("lease_type",
  717. offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_INT32)));
  718. parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("iaid",
  719. offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_INT32)));
  720. parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("prefix_len",
  721. offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_INT32)));
  722. parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("fqdn_fwd",
  723. offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_BOOL)));
  724. parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("fqdn_rev",
  725. offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_BOOL)));
  726. parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("hostname",
  727. offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_STRING)));
  728. parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("hwaddr",
  729. offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_BYTES)));
  730. parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("hwtype",
  731. offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_INT32)));
  732. parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("hwaddr_source",
  733. offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_INT32)));
  734. parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("state",
  735. offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_INT32)));
  736. parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("limit",
  737. offset++, EXCHANGE_DATA_TYPE_IO_IN_OUT, EXCHANGE_DATA_TYPE_INT32)));
  738. parameters_.push_back(ExchangeColumnInfoPtr(new ExchangeColumnInfo("[applied]",
  739. offset++, EXCHANGE_DATA_TYPE_IO_OUT, EXCHANGE_DATA_TYPE_BOOL)));
  740. BOOST_ASSERT(parameters_.size() == MAX_COLUMNS);
  741. }
  742. /// @brief Create CQL_BIND objects for Lease6 Pointer
  743. ///
  744. /// Fills in the CQL_BIND array for sending data in the Lease6 object to
  745. /// the database.
  746. void createBindForSend(const Lease6Ptr& lease, CqlDataArray& data) {
  747. if (!lease) {
  748. isc_throw(BadValue, "createBindForSend:: Lease6 object is NULL");
  749. }
  750. // Store lease object to ensure it remains valid.
  751. lease_ = lease;
  752. // Set up the structures for the various components of the lease4
  753. // structure.
  754. try {
  755. // address: varchar
  756. std::string text_buffer = lease_->addr_.toText();
  757. addr6_length_ = text_buffer.size();
  758. if (addr6_length_ >= sizeof(addr6_buffer_)) {
  759. isc_throw(BadValue, "address value is too large: " <<
  760. text_buffer);
  761. }
  762. if (addr6_length_) {
  763. memcpy(addr6_buffer_, text_buffer.c_str(), addr6_length_);
  764. }
  765. addr6_buffer_[addr6_length_] = '\0';
  766. data.add(addr6_buffer_);
  767. // duid: blob
  768. if (!lease_->duid_) {
  769. isc_throw(DbOperationError, "lease6 for address " <<
  770. addr6_buffer_ << " is missing mandatory client-id");
  771. }
  772. duid_ = lease_->duid_->getDuid();
  773. duid_length_ = duid_.size();
  774. data.add(&duid_);
  775. // valid lifetime: bigint
  776. valid_lifetime_ = lease_->valid_lft_;
  777. data.add(&valid_lifetime_);
  778. // expire: bigint
  779. // The lease structure holds the client last transmission time (cltt_)
  780. // For convenience for external tools, this is converted to lease
  781. // expiry time (expire). The relationship is given by:
  782. //
  783. // expire = cltt_ + valid_lft_
  784. CqlLeaseExchange::convertToDatabaseTime(lease_->cltt_,
  785. lease_->valid_lft_, expire_);
  786. data.add(&expire_);
  787. // subnet_id: int
  788. // Can use lease_->subnet_id_ directly as it is of type uint32_t.
  789. subnet_id_ = lease_->subnet_id_;
  790. data.add(&subnet_id_);
  791. // pref_lifetime: bigint
  792. // Can use lease_->preferred_lft_ directly as it is of type uint32_t.
  793. pref_lifetime_ = lease_->preferred_lft_;
  794. data.add(&pref_lifetime_);
  795. // lease_type: int
  796. // Must convert to uint8_t as lease_->type_ is a LeaseType variable.
  797. lease_type_ = lease_->type_;
  798. data.add(&lease_type_);
  799. // iaid: int
  800. // Can use lease_->iaid_ directly as it is of type uint32_t.
  801. iaid_ = lease_->iaid_;
  802. data.add(&iaid_);
  803. // prefix_len: int
  804. // Can use lease_->prefixlen_ directly as it is uint32_t.
  805. prefixlen_ = lease_->prefixlen_;
  806. data.add(&prefixlen_);
  807. // fqdn_fwd: boolean
  808. fqdn_fwd_ = lease_->fqdn_fwd_;
  809. data.add(&fqdn_fwd_);
  810. // fqdn_rev: boolean
  811. fqdn_rev_ = lease_->fqdn_rev_;
  812. data.add(&fqdn_rev_);
  813. // hostname: varchar
  814. hostname_length_ = lease_->hostname_.length();
  815. if (hostname_length_ >= sizeof(hostname_buffer_)) {
  816. isc_throw(BadValue, "hostname value is too large: " <<
  817. lease_->hostname_.c_str());
  818. }
  819. if (hostname_length_) {
  820. memcpy(hostname_buffer_, lease_->hostname_.c_str(),
  821. hostname_length_);
  822. }
  823. hostname_buffer_[hostname_length_] = '\0';
  824. data.add(hostname_buffer_);
  825. // hwaddr: blob
  826. HWAddrPtr hwaddr = lease_->hwaddr_;
  827. if (hwaddr) {
  828. if (hwaddr->hwaddr_.size() > HWAddr::MAX_HWADDR_LEN) {
  829. isc_throw(DbOperationError, "Hardware address length : "
  830. << lease_->hwaddr_->hwaddr_.size()
  831. << " exceeds maximum allowed of: "
  832. << HWAddr::MAX_HWADDR_LEN);
  833. }
  834. hwaddr_ = hwaddr->hwaddr_;
  835. } else {
  836. hwaddr_.clear();
  837. }
  838. hwaddr_length_ = hwaddr_.size();
  839. data.add(&hwaddr_);
  840. // hwtype: int
  841. if (hwaddr) {
  842. hwtype_ = lease->hwaddr_->htype_;
  843. } else {
  844. hwtype_ = 0;
  845. }
  846. data.add(&hwtype_);
  847. // hwaddr_source: int
  848. if (hwaddr) {
  849. hwaddr_source_ = lease->hwaddr_->source_;
  850. } else {
  851. hwaddr_source_ = 0;
  852. }
  853. data.add(&hwaddr_source_);
  854. // state: int
  855. state_ = lease_->state_;
  856. data.add(&state_);
  857. } catch (const std::exception& ex) {
  858. isc_throw(DbOperationError,
  859. "Could not create bind array from Lease6: "
  860. << lease_->addr_.toText() << ", reason: " << ex.what());
  861. }
  862. }
  863. /// @brief Create BIND array to receive data
  864. ///
  865. /// Creates a CQL_BIND array to receive Lease6 data from the database.
  866. Lease6Ptr createBindForReceive(const CassRow* row) {
  867. try {
  868. unsigned char* duid_buffer = NULL;
  869. unsigned char* hwaddr_buffer = NULL;
  870. const char* address_buffer = NULL;
  871. const char* hostname_buffer = NULL;
  872. CqlDataArray data;
  873. CqlDataArray size;
  874. // address: varchar
  875. data.add(reinterpret_cast<void*>(&address_buffer));
  876. size.add(reinterpret_cast<void*>(&addr6_length_));
  877. // duid: blob
  878. data.add(reinterpret_cast<void*>(&duid_buffer));
  879. size.add(reinterpret_cast<void*>(&duid_length_));
  880. // valid_lifetime_: bigint
  881. data.add(reinterpret_cast<void*>(&valid_lifetime_));
  882. size.add(NULL);
  883. // expire: bigint
  884. data.add(reinterpret_cast<void*>(&expire_));
  885. size.add(NULL);
  886. // subnet_id: int
  887. data.add(reinterpret_cast<void*>(&subnet_id_));
  888. size.add(NULL);
  889. // pref_lifetime: bigint
  890. data.add(reinterpret_cast<void*>(&pref_lifetime_));
  891. size.add(NULL);
  892. // lease_type: int
  893. data.add(reinterpret_cast<void*>(&lease_type_));
  894. size.add(NULL);
  895. // iaid: int
  896. data.add(reinterpret_cast<void*>(&iaid_));
  897. size.add(NULL);
  898. // prefix_len: int
  899. data.add(reinterpret_cast<void*>(&prefixlen_));
  900. size.add(NULL);
  901. // fqdn_fwd: boolean
  902. data.add(reinterpret_cast<void*>(&fqdn_fwd_));
  903. size.add(NULL);
  904. // fqdn_rev: boolean
  905. data.add(reinterpret_cast<void*>(&fqdn_rev_));
  906. size.add(NULL);
  907. // hostname: varchar
  908. data.add(reinterpret_cast<void*>(&hostname_buffer));
  909. size.add(reinterpret_cast<void*>(&hostname_length_));
  910. // hwaddr: blob
  911. data.add(reinterpret_cast<void*>(&hwaddr_buffer));
  912. size.add(reinterpret_cast<void*>(&hwaddr_length_));
  913. // hwtype: int
  914. data.add(reinterpret_cast<void*>(&hwtype_));
  915. size.add(NULL);
  916. // hwaddr_source: int
  917. data.add(reinterpret_cast<void*>(&hwaddr_source_));
  918. size.add(NULL);
  919. // state: int
  920. data.add(reinterpret_cast<void*>(&state_));
  921. size.add(NULL);
  922. for (size_t i = 0; i < data.size(); i++) {
  923. CqlLeaseMgr::getData(row, i, data, size, i, *this);
  924. }
  925. // address: varchar
  926. if (addr6_length_ >= sizeof(addr6_buffer_)) {
  927. isc_throw(BadValue, "address value is too large: " <<
  928. address_buffer);
  929. }
  930. if (addr6_length_) {
  931. memcpy(addr6_buffer_, address_buffer, addr6_length_);
  932. }
  933. addr6_buffer_[addr6_length_] = '\0';
  934. // duid: blob
  935. duid_.assign(duid_buffer, duid_buffer + duid_length_);
  936. // hostname: varchar
  937. if (hostname_length_ >= sizeof(hostname_buffer_)) {
  938. isc_throw(BadValue, "hostname value is too large: " <<
  939. hostname_buffer);
  940. }
  941. if (hostname_length_) {
  942. memcpy(hostname_buffer_, hostname_buffer, hostname_length_);
  943. }
  944. hostname_buffer_[hostname_length_] = '\0';
  945. // hwaddr: blob
  946. hwaddr_.assign(hwaddr_buffer, hwaddr_buffer + hwaddr_length_);
  947. if (lease_type_ != Lease::TYPE_NA && lease_type_ != Lease::TYPE_TA &&
  948. lease_type_ != Lease::TYPE_PD) {
  949. isc_throw(BadValue, "invalid lease type returned (" <<
  950. static_cast<int>(lease_type_) << ") for lease with "
  951. << "address " << addr6_buffer_ << ". Only 0, 1, or 2 are "
  952. << "allowed");
  953. }
  954. isc::asiolink::IOAddress addr(addr6_buffer_);
  955. DuidPtr duid(new DUID(duid_));
  956. HWAddrPtr hwaddr;
  957. if (hwaddr_.size()) {
  958. hwaddr.reset(new HWAddr(hwaddr_, hwtype_));
  959. hwaddr->source_ = hwaddr_source_;
  960. }
  961. std::string hostname(hostname_buffer_,
  962. hostname_buffer_ + hostname_length_);
  963. // Create the lease and set the cltt (after converting from the
  964. // expire time retrieved from the database).
  965. Lease6Ptr result(new Lease6(static_cast<Lease::Type>(lease_type_),
  966. addr, duid, iaid_, pref_lifetime_,
  967. valid_lifetime_, 0, 0, subnet_id_,
  968. fqdn_fwd_, fqdn_rev_, hostname, hwaddr,
  969. prefixlen_));
  970. time_t cltt = 0;
  971. CqlLeaseExchange::convertFromDatabaseTime(expire_, valid_lifetime_,
  972. cltt);
  973. result->cltt_ = cltt;
  974. result->state_ = state_;
  975. return (result);
  976. } catch (const std::exception& ex) {
  977. isc_throw(DbOperationError,
  978. "Could not convert data to Lease4, reason: "
  979. << ex.what());
  980. }
  981. return (Lease6Ptr());
  982. }
  983. private:
  984. Lease6Ptr lease_; ///< Pointer to lease object
  985. char addr6_buffer_[ADDRESS6_TEXT_MAX_LEN + 1]; ///< Character
  986. ///< array form of V6 address
  987. unsigned long addr6_length_; ///< Length of the address
  988. std::vector<uint8_t> duid_; ///< Client identification
  989. uint8_t duid_buffer_[DUID::MAX_DUID_LEN]; ///< Buffer form of DUID
  990. unsigned long duid_length_; ///< Length of the DUID
  991. uint32_t iaid_; ///< Identity association ID
  992. uint32_t lease_type_; ///< Lease type
  993. uint32_t prefixlen_; ///< Prefix length
  994. uint32_t pref_lifetime_; ///< Preferred lifetime
  995. bool hwaddr_null_; ///< Used when HWAddr is null
  996. uint32_t hwtype_; ///< Hardware type
  997. uint32_t hwaddr_source_; ///< Source of the hardware address
  998. };
  999. CqlLeaseMgr::CqlLeaseMgr(const DatabaseConnection::ParameterMap& parameters)
  1000. : LeaseMgr(), dbconn_(parameters), exchange4_(new CqlLease4Exchange()),
  1001. exchange6_(new CqlLease6Exchange()), versionExchange_(new CqlVersionExchange()) {
  1002. dbconn_.openDatabase();
  1003. dbconn_.prepareStatements(CqlLeaseMgr::tagged_statements_);
  1004. }
  1005. CqlLeaseMgr::~CqlLeaseMgr() {
  1006. // There is no need to close the database in this destructor: it is
  1007. // closed in the destructor of the dbconn_ member variable.
  1008. }
  1009. std::string
  1010. CqlLeaseMgr::getDBVersion() {
  1011. std::stringstream tmp;
  1012. tmp << "CQL backend " << CQL_SCHEMA_VERSION_MAJOR;
  1013. tmp << "." << CQL_SCHEMA_VERSION_MINOR;
  1014. tmp << ", library " << "cassandra_static";
  1015. return (tmp.str());
  1016. }
  1017. ExchangeDataType
  1018. CqlLeaseMgr::getDataType(const StatementIndex stindex, int pindex,
  1019. const SqlExchange& exchange) {
  1020. if (CqlLeaseMgr::tagged_statements_[stindex].params_ &&
  1021. CqlLeaseMgr::tagged_statements_[stindex].params_[pindex]) {
  1022. const ExchangeColumnInfoContainerName& idx = exchange.parameters_.get<1>();
  1023. const ExchangeColumnInfoContainerNameRange& range =
  1024. idx.equal_range(CqlLeaseMgr::tagged_statements_[stindex].params_[pindex]);
  1025. if (std::distance(range.first, range.second) > 0) {
  1026. return (*range.first)->type_;
  1027. }
  1028. }
  1029. return EXCHANGE_DATA_TYPE_NONE;
  1030. }
  1031. void
  1032. CqlLeaseMgr::bindData(CassStatement* statement, const StatementIndex stindex,
  1033. CqlDataArray& data, const SqlExchange& exchange) {
  1034. if (CqlLeaseMgr::tagged_statements_[stindex].params_ == NULL) {
  1035. return;
  1036. }
  1037. for (int i = 0; CqlLeaseMgr::tagged_statements_[stindex].params_[i]; i++) {
  1038. ExchangeDataType type = CqlLeaseMgr::getDataType(stindex, i, exchange);
  1039. if (type >= sizeof(CqlFunctions) / sizeof(CqlFunctions[0])) {
  1040. isc_throw(BadValue, "index " << stindex << " out of bounds");
  1041. }
  1042. CqlFunctions[type].sqlBindFunction_(statement, i, data.values_[i]);
  1043. }
  1044. }
  1045. void
  1046. CqlLeaseMgr::getData(const CassRow* row, const int pindex, CqlDataArray& data,
  1047. CqlDataArray& size, const int dindex, const SqlExchange& exchange) {
  1048. if (pindex >= exchange.parameters_.size()) {
  1049. return;
  1050. }
  1051. const ExchangeColumnInfoContainerIndex& idx = exchange.parameters_.get<2>();
  1052. const ExchangeColumnInfoContainerIndexRange& range = idx.equal_range(pindex);
  1053. if (std::distance(range.first, range.second) > 0) {
  1054. std::string name = (*range.first)->name_;
  1055. ExchangeDataType type = (*range.first)->type_;
  1056. const CassValue* value = cass_row_get_column_by_name(row, name.c_str());
  1057. if (NULL == value) {
  1058. isc_throw(BadValue, "column name " << name << " doesn't exist");
  1059. }
  1060. if (type >= sizeof(CqlFunctions) / sizeof(CqlFunctions[0])) {
  1061. isc_throw(BadValue, "index " << type << " out of bounds");
  1062. }
  1063. CqlFunctions[type].sqlGetFunction_(value, data.values_[dindex],
  1064. reinterpret_cast<size_t *>(size.values_[dindex]));
  1065. }
  1066. }
  1067. bool
  1068. CqlLeaseMgr::addLeaseCommon(StatementIndex stindex,
  1069. CqlDataArray& data, CqlLeaseExchange& exchange) {
  1070. CassError rc;
  1071. CassStatement* statement = NULL;
  1072. CassFuture* future = NULL;
  1073. statement = cass_prepared_bind(dbconn_.statements_[stindex]);
  1074. if (NULL == statement) {
  1075. isc_throw(DbOperationError, "unable to bind statement");
  1076. }
  1077. CqlLeaseMgr::bindData(statement, stindex, data, exchange);
  1078. future = cass_session_execute(dbconn_.session_, statement);
  1079. if (NULL == future) {
  1080. cass_statement_free(statement);
  1081. isc_throw(DbOperationError, "unable to execute statement");
  1082. }
  1083. cass_future_wait(future);
  1084. std::string error;
  1085. dbconn_.checkStatementError(error, future, stindex, "unable to INSERT");
  1086. rc = cass_future_error_code(future);
  1087. if (rc != CASS_OK) {
  1088. cass_future_free(future);
  1089. cass_statement_free(statement);
  1090. return false;
  1091. }
  1092. // Check if statement has been applied.
  1093. const CassResult* resultCollection = cass_future_get_result(future);
  1094. CassIterator* rows = cass_iterator_from_result(resultCollection);
  1095. CqlDataArray appliedData;
  1096. CqlDataArray appliedSize;
  1097. bool applied = false;
  1098. while (cass_iterator_next(rows)) {
  1099. const CassRow* row = cass_iterator_get_row(rows);
  1100. // [applied]: bool
  1101. appliedData.add(reinterpret_cast<void*>(&applied));
  1102. appliedSize.add(NULL);
  1103. CqlLeaseMgr::getData(row, exchange.parameters_.size() - 1, appliedData,
  1104. appliedSize, 0, exchange);
  1105. }
  1106. // Free resources.
  1107. cass_iterator_free(rows);
  1108. cass_result_free(resultCollection);
  1109. cass_future_free(future);
  1110. cass_statement_free(statement);
  1111. return applied;
  1112. }
  1113. bool
  1114. CqlLeaseMgr::addLease(const Lease4Ptr& lease) {
  1115. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  1116. DHCPSRV_CQL_ADD_ADDR4).arg(lease->addr_.toText());
  1117. CqlDataArray data;
  1118. exchange4_->createBindForSend(lease, data);
  1119. return (addLeaseCommon(INSERT_LEASE4, data, *exchange4_));
  1120. }
  1121. bool
  1122. CqlLeaseMgr::addLease(const Lease6Ptr& lease) {
  1123. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  1124. DHCPSRV_CQL_ADD_ADDR6).arg(lease->addr_.toText());
  1125. CqlDataArray data;
  1126. exchange6_->createBindForSend(lease, data);
  1127. return (addLeaseCommon(INSERT_LEASE6, data, *exchange6_));
  1128. }
  1129. template <typename Exchange, typename LeaseCollection>
  1130. void CqlLeaseMgr::getLeaseCollection(StatementIndex stindex,
  1131. CqlDataArray& data,
  1132. Exchange& exchange,
  1133. LeaseCollection& result,
  1134. bool single) const {
  1135. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  1136. DHCPSRV_CQL_GET_ADDR4).arg(dbconn_.tagged_statements_[stindex].name_);
  1137. CassError rc;
  1138. CassStatement* statement = NULL;
  1139. CassFuture* future = NULL;
  1140. const CqlLeaseExchange& leaseExchange = static_cast<CqlLeaseExchange>(*exchange);
  1141. statement = cass_prepared_bind(dbconn_.statements_[stindex]);
  1142. if (NULL == statement) {
  1143. isc_throw(DbOperationError, "unable to bind statement");
  1144. }
  1145. CqlLeaseMgr::bindData(statement, stindex, data, leaseExchange);
  1146. future = cass_session_execute(dbconn_.session_, statement);
  1147. if (NULL == future) {
  1148. cass_statement_free(statement);
  1149. isc_throw(DbOperationError, "unable to execute statement");
  1150. }
  1151. cass_future_wait(future);
  1152. std::string error;
  1153. dbconn_.checkStatementError(error, future, "unable to GET");
  1154. rc = cass_future_error_code(future);
  1155. if (rc != CASS_OK) {
  1156. cass_future_free(future);
  1157. cass_statement_free(statement);
  1158. isc_throw(DbOperationError, error);
  1159. }
  1160. const CassResult* resultCollection = cass_future_get_result(future);
  1161. CassIterator* rows = cass_iterator_from_result(resultCollection);
  1162. int rowCount = 0;
  1163. while (cass_iterator_next(rows)) {
  1164. rowCount++;
  1165. if (single && rowCount > 1) {
  1166. result.clear();
  1167. break;
  1168. }
  1169. const CassRow* row = cass_iterator_get_row(rows);
  1170. result.push_back(exchange->createBindForReceive(row));
  1171. }
  1172. cass_iterator_free(rows);
  1173. cass_result_free(resultCollection);
  1174. cass_future_free(future);
  1175. cass_statement_free(statement);
  1176. if (single && rowCount > 1) {
  1177. isc_throw(MultipleRecords, "multiple records were found in the "
  1178. "database where only one was expected for query "
  1179. << dbconn_.tagged_statements_[stindex].name_);
  1180. }
  1181. }
  1182. void
  1183. CqlLeaseMgr::getLease(StatementIndex stindex, CqlDataArray& data,
  1184. Lease4Ptr& result) const {
  1185. // Create appropriate collection object and get all leases matching
  1186. // the selection criteria. The "single" parameter is true to indicate
  1187. // that the called method should throw an exception if multiple
  1188. // matching records are found: this particular method is called when only
  1189. // one or zero matches is expected.
  1190. Lease4Collection collection;
  1191. getLeaseCollection(stindex, data, exchange4_, collection, true);
  1192. // Return single record if present, else clear the lease.
  1193. if (collection.empty()) {
  1194. result.reset();
  1195. } else {
  1196. result = *collection.begin();
  1197. }
  1198. }
  1199. void
  1200. CqlLeaseMgr::getLease(StatementIndex stindex, CqlDataArray& data,
  1201. Lease6Ptr& result) const {
  1202. // Create appropriate collection object and get all leases matching
  1203. // the selection criteria. The "single" parameter is true to indicate
  1204. // that the called method should throw an exception if multiple
  1205. // matching records are found: this particular method is called when only
  1206. // one or zero matches is expected.
  1207. Lease6Collection collection;
  1208. getLeaseCollection(stindex, data, exchange6_, collection, true);
  1209. // Return single record if present, else clear the lease.
  1210. if (collection.empty()) {
  1211. result.reset();
  1212. } else {
  1213. result = *collection.begin();
  1214. }
  1215. }
  1216. // Basic lease access methods. Obtain leases from the database using various
  1217. // criteria.
  1218. Lease4Ptr
  1219. CqlLeaseMgr::getLease4(const isc::asiolink::IOAddress& addr) const {
  1220. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  1221. DHCPSRV_CQL_GET_ADDR4).arg(addr.toText());
  1222. // Set up the WHERE clause value
  1223. CqlDataArray data;
  1224. uint32_t addr4_data = addr.toUint32();
  1225. data.add(&addr4_data);
  1226. // Get the data
  1227. Lease4Ptr result;
  1228. getLease(GET_LEASE4_ADDR, data, result);
  1229. return (result);
  1230. }
  1231. Lease4Collection
  1232. CqlLeaseMgr::getLease4(const HWAddr& hwaddr) const {
  1233. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  1234. DHCPSRV_CQL_GET_HWADDR).arg(hwaddr.toText());
  1235. // Set up the WHERE clause value
  1236. CqlDataArray data;
  1237. std::vector<uint8_t>hwaddr_data = hwaddr.hwaddr_;
  1238. data.add(&hwaddr_data);
  1239. // Get the data
  1240. Lease4Collection result;
  1241. getLeaseCollection(GET_LEASE4_HWADDR, data, result);
  1242. return (result);
  1243. }
  1244. Lease4Ptr
  1245. CqlLeaseMgr::getLease4(const HWAddr& hwaddr, SubnetID subnet_id) const {
  1246. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  1247. DHCPSRV_CQL_GET_SUBID_HWADDR)
  1248. .arg(subnet_id).arg(hwaddr.toText());
  1249. // Set up the WHERE clause value
  1250. CqlDataArray data;
  1251. std::vector<uint8_t>hwaddr_data = hwaddr.hwaddr_;
  1252. data.add(&hwaddr_data);
  1253. uint32_t subnet_id_data = subnet_id;
  1254. data.add(&subnet_id_data);
  1255. // Get the data
  1256. Lease4Ptr result;
  1257. getLease(GET_LEASE4_HWADDR_SUBID, data, result);
  1258. return (result);
  1259. }
  1260. Lease4Collection
  1261. CqlLeaseMgr::getLease4(const ClientId& clientid) const {
  1262. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  1263. DHCPSRV_CQL_GET_CLIENTID).arg(clientid.toText());
  1264. // Set up the WHERE clause value
  1265. CqlDataArray data;
  1266. std::vector<uint8_t> client_id_data = clientid.getClientId();
  1267. data.add(&client_id_data);
  1268. // Get the data
  1269. Lease4Collection result;
  1270. getLeaseCollection(GET_LEASE4_CLIENTID, data, result);
  1271. return (result);
  1272. }
  1273. Lease4Ptr
  1274. CqlLeaseMgr::getLease4(const ClientId& clientid, const HWAddr& hwaddr,
  1275. SubnetID subnet_id) const {
  1276. /// This function is currently not implemented because allocation engine
  1277. /// searches for the lease using HW address or client identifier.
  1278. /// It never uses both parameters in the same time. We need to
  1279. /// consider if this function is needed at all.
  1280. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  1281. DHCPSRV_CQL_GET_CLIENTID_HWADDR_SUBID).arg(clientid.toText())
  1282. .arg(hwaddr.toText()).arg(subnet_id);
  1283. isc_throw(NotImplemented, "The CqlLeaseMgr::getLease4 function was"
  1284. " called, but it is not implemented");
  1285. }
  1286. Lease4Ptr
  1287. CqlLeaseMgr::getLease4(const ClientId& clientid, SubnetID subnet_id) const {
  1288. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  1289. DHCPSRV_CQL_GET_SUBID_CLIENTID)
  1290. .arg(subnet_id).arg(clientid.toText());
  1291. // Set up the WHERE clause value
  1292. CqlDataArray data;
  1293. std::vector<uint8_t> client_id_data = clientid.getClientId();
  1294. data.add(&client_id_data);
  1295. uint32_t subnet_id_data = subnet_id;
  1296. data.add(&subnet_id_data);
  1297. // Get the data
  1298. Lease4Ptr result;
  1299. getLease(GET_LEASE4_CLIENTID_SUBID, data, result);
  1300. return (result);
  1301. }
  1302. Lease6Ptr
  1303. CqlLeaseMgr::getLease6(Lease::Type lease_type,
  1304. const isc::asiolink::IOAddress& addr) const {
  1305. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  1306. DHCPSRV_CQL_GET_ADDR6).arg(addr.toText())
  1307. .arg(lease_type);
  1308. // Set up the WHERE clause value
  1309. CqlDataArray data;
  1310. std::string text_buffer = addr.toText();
  1311. uint32_t addr6_length = text_buffer.size();
  1312. char addr6_buffer[ADDRESS6_TEXT_MAX_LEN + 1];
  1313. if (addr6_length >= sizeof(addr6_buffer)) {
  1314. isc_throw(BadValue, "address value is too large: " << text_buffer);
  1315. }
  1316. if (addr6_length) {
  1317. memcpy(addr6_buffer, text_buffer.c_str(), addr6_length);
  1318. }
  1319. addr6_buffer[addr6_length] = '\0';
  1320. data.add(addr6_buffer);
  1321. uint32_t lease_type_data = lease_type;
  1322. data.add(&lease_type_data);
  1323. Lease6Ptr result;
  1324. getLease(GET_LEASE6_ADDR, data, result);
  1325. return (result);
  1326. }
  1327. Lease6Collection
  1328. CqlLeaseMgr::getLeases6(Lease::Type lease_type,
  1329. const DUID& duid, uint32_t iaid) const {
  1330. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  1331. DHCPSRV_CQL_GET_IAID_DUID).arg(iaid).arg(duid.toText())
  1332. .arg(lease_type);
  1333. // Set up the WHERE clause value
  1334. CqlDataArray data;
  1335. std::vector<uint8_t> duid_data = duid.getDuid();
  1336. data.add(&duid_data);
  1337. uint32_t iaid_data = iaid;
  1338. data.add(&iaid_data);
  1339. uint32_t lease_type_data = lease_type;
  1340. data.add(&lease_type_data);
  1341. // ... and get the data
  1342. Lease6Collection result;
  1343. getLeaseCollection(GET_LEASE6_DUID_IAID, data, result);
  1344. return (result);
  1345. }
  1346. Lease6Collection
  1347. CqlLeaseMgr::getLeases6(Lease::Type lease_type,
  1348. const DUID& duid, uint32_t iaid,
  1349. SubnetID subnet_id) const {
  1350. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  1351. DHCPSRV_CQL_GET_IAID_SUBID_DUID)
  1352. .arg(iaid).arg(subnet_id).arg(duid.toText())
  1353. .arg(lease_type);
  1354. // Set up the WHERE clause value
  1355. CqlDataArray data;
  1356. std::vector<uint8_t> duid_data = duid.getDuid();
  1357. data.add(&duid_data);
  1358. uint32_t iaid_data = iaid;
  1359. data.add(&iaid_data);
  1360. uint32_t subnet_id_data = subnet_id;
  1361. data.add(&subnet_id_data);
  1362. uint32_t lease_type_data = lease_type;
  1363. data.add(&lease_type_data);
  1364. // ... and get the data
  1365. Lease6Collection result;
  1366. getLeaseCollection(GET_LEASE6_DUID_IAID_SUBID, data, result);
  1367. return (result);
  1368. }
  1369. void
  1370. CqlLeaseMgr::getExpiredLeases6(Lease6Collection& expired_leases,
  1371. const size_t max_leases) const {
  1372. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_GET_EXPIRED6)
  1373. .arg(max_leases);
  1374. getExpiredLeasesCommon(expired_leases, max_leases, GET_LEASE6_EXPIRE);
  1375. }
  1376. void
  1377. CqlLeaseMgr::getExpiredLeases4(Lease4Collection& expired_leases,
  1378. const size_t max_leases) const {
  1379. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_GET_EXPIRED4)
  1380. .arg(max_leases);
  1381. getExpiredLeasesCommon(expired_leases, max_leases, GET_LEASE4_EXPIRE);
  1382. }
  1383. template<typename LeaseCollection>
  1384. void
  1385. CqlLeaseMgr::getExpiredLeasesCommon(LeaseCollection& expired_leases,
  1386. const size_t max_leases,
  1387. StatementIndex statement_index) const {
  1388. // Set up the WHERE clause value
  1389. uint32_t keepState = Lease::STATE_EXPIRED_RECLAIMED;
  1390. uint64_t timestamp = static_cast<int64_t>(time(NULL));
  1391. // If the number of leases is 0, we will return all leases. This is
  1392. // achieved by setting the limit to a very high value.
  1393. uint32_t limit = max_leases > 0 ? static_cast<int32_t>(max_leases) :
  1394. std::numeric_limits<int32_t>::max();
  1395. for (uint32_t state = Lease::STATE_DEFAULT;
  1396. state <= Lease::STATE_EXPIRED_RECLAIMED; state++) {
  1397. if (state == keepState) {
  1398. continue;
  1399. }
  1400. LeaseCollection tempCollection;
  1401. CqlDataArray data;
  1402. data.add(&state);
  1403. data.add(&timestamp);
  1404. data.add(&limit);
  1405. // Retrieve leases from the database.
  1406. getLeaseCollection(statement_index, data, tempCollection);
  1407. typedef typename LeaseCollection::iterator LeaseCollectionIt;
  1408. for (LeaseCollectionIt it = tempCollection.begin();
  1409. it != tempCollection.end(); ++it) {
  1410. expired_leases.push_back((*it));
  1411. }
  1412. }
  1413. }
  1414. template <typename LeasePtr>
  1415. void
  1416. CqlLeaseMgr::updateLeaseCommon(StatementIndex stindex,
  1417. CqlDataArray& data,
  1418. const LeasePtr&, CqlLeaseExchange& exchange) {
  1419. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  1420. DHCPSRV_CQL_ADD_ADDR4).arg(dbconn_.tagged_statements_[stindex].name_);
  1421. CassError rc;
  1422. CassStatement* statement = NULL;
  1423. CassFuture* future = NULL;
  1424. statement = cass_prepared_bind(dbconn_.statements_[stindex]);
  1425. if (NULL == statement) {
  1426. isc_throw(DbOperationError, "unable to bind statement");
  1427. }
  1428. CqlLeaseMgr::bindData(statement, stindex, data, exchange);
  1429. future = cass_session_execute(dbconn_.session_, statement);
  1430. if (NULL == future) {
  1431. cass_statement_free(statement);
  1432. isc_throw(DbOperationError, "unable to execute statement");
  1433. }
  1434. cass_future_wait(future);
  1435. std::string error;
  1436. dbconn_.checkStatementError(error, future, stindex, "unable to UPDATE");
  1437. rc = cass_future_error_code(future);
  1438. if (rc != CASS_OK) {
  1439. cass_future_free(future);
  1440. cass_statement_free(statement);
  1441. isc_throw(DbOperationError, error);
  1442. }
  1443. // Check if statement has been applied.
  1444. const CassResult* resultCollection = cass_future_get_result(future);
  1445. CassIterator* rows = cass_iterator_from_result(resultCollection);
  1446. CqlDataArray appliedData;
  1447. CqlDataArray appliedSize;
  1448. bool applied = false;
  1449. while (cass_iterator_next(rows)) {
  1450. const CassRow* row = cass_iterator_get_row(rows);
  1451. // [applied]: bool
  1452. appliedData.add(reinterpret_cast<void*>(&applied));
  1453. appliedSize.add(NULL);
  1454. CqlLeaseMgr::getData(row, exchange.parameters_.size() - 1, appliedData,
  1455. appliedSize, 0, exchange);
  1456. }
  1457. // Free resources.
  1458. cass_iterator_free(rows);
  1459. cass_result_free(resultCollection);
  1460. cass_future_free(future);
  1461. cass_statement_free(statement);
  1462. if (!applied) {
  1463. isc_throw(NoSuchLease, "Statement has not been applied.");
  1464. }
  1465. }
  1466. void
  1467. CqlLeaseMgr::updateLease4(const Lease4Ptr& lease) {
  1468. const StatementIndex stindex = UPDATE_LEASE4;
  1469. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  1470. DHCPSRV_CQL_UPDATE_ADDR4).arg(lease->addr_.toText());
  1471. // Create the BIND array for the data being updated
  1472. CqlDataArray data;
  1473. exchange4_->createBindForSend(lease, data);
  1474. data.remove(0);
  1475. // Set up the WHERE clause and append it to the SQL_BIND array
  1476. uint32_t addr4_data = lease->addr_.toUint32();
  1477. data.add(&addr4_data);
  1478. // Drop to common update code
  1479. updateLeaseCommon(stindex, data, lease, *exchange4_);
  1480. }
  1481. void
  1482. CqlLeaseMgr::updateLease6(const Lease6Ptr& lease) {
  1483. const StatementIndex stindex = UPDATE_LEASE6;
  1484. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  1485. DHCPSRV_CQL_UPDATE_ADDR6).arg(lease->addr_.toText());
  1486. // Create the BIND array for the data being updated
  1487. CqlDataArray data;
  1488. exchange6_->createBindForSend(lease, data);
  1489. data.remove(0);
  1490. // Set up the WHERE clause and append it to the BIND array
  1491. std::string text_buffer = lease->addr_.toText();
  1492. uint32_t addr6_length = text_buffer.size();
  1493. char addr6_buffer[ADDRESS6_TEXT_MAX_LEN + 1];
  1494. if (addr6_length >= sizeof(addr6_buffer)) {
  1495. isc_throw(BadValue, "address value is too large: " << text_buffer);
  1496. }
  1497. if (addr6_length) {
  1498. memcpy(addr6_buffer, text_buffer.c_str(), addr6_length);
  1499. }
  1500. addr6_buffer[addr6_length] = '\0';
  1501. data.add(addr6_buffer);
  1502. // Drop to common update code
  1503. updateLeaseCommon(stindex, data, lease, *exchange6_);
  1504. }
  1505. bool
  1506. CqlLeaseMgr::deleteLeaseCommon(StatementIndex stindex,
  1507. CqlDataArray& data, CqlLeaseExchange& exchange) {
  1508. CassError rc;
  1509. CassStatement* statement = NULL;
  1510. CassFuture* future = NULL;
  1511. statement = cass_prepared_bind(dbconn_.statements_[stindex]);
  1512. if (NULL == statement) {
  1513. isc_throw(DbOperationError, "unable to bind statement");
  1514. }
  1515. CqlLeaseMgr::bindData(statement, stindex, data, exchange);
  1516. future = cass_session_execute(dbconn_.session_, statement);
  1517. if (NULL == future) {
  1518. cass_statement_free(statement);
  1519. isc_throw(DbOperationError, "unable to execute statement");
  1520. }
  1521. cass_future_wait(future);
  1522. std::string error;
  1523. dbconn_.checkStatementError(error, future, stindex, "unable to DELETE");
  1524. rc = cass_future_error_code(future);
  1525. if (rc != CASS_OK) {
  1526. cass_future_free(future);
  1527. cass_statement_free(statement);
  1528. isc_throw(DbOperationError, error);
  1529. }
  1530. // Check if statement has been applied.
  1531. const CassResult* resultCollection = cass_future_get_result(future);
  1532. CassIterator* rows = cass_iterator_from_result(resultCollection);
  1533. CqlDataArray appliedData;
  1534. CqlDataArray appliedSize;
  1535. bool applied = false;
  1536. while (cass_iterator_next(rows)) {
  1537. const CassRow* row = cass_iterator_get_row(rows);
  1538. // [applied]: bool
  1539. appliedData.add(reinterpret_cast<void*>(&applied));
  1540. appliedSize.add(NULL);
  1541. CqlLeaseMgr::getData(row, exchange.parameters_.size() - 1, appliedData,
  1542. appliedSize, 0, exchange);
  1543. }
  1544. // Free resources.
  1545. cass_iterator_free(rows);
  1546. cass_result_free(resultCollection);
  1547. cass_future_free(future);
  1548. cass_statement_free(statement);
  1549. return applied;
  1550. }
  1551. bool
  1552. CqlLeaseMgr::deleteLease(const isc::asiolink::IOAddress& addr) {
  1553. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  1554. DHCPSRV_CQL_DELETE_ADDR).arg(addr.toText());
  1555. // Set up the WHERE clause value
  1556. CqlDataArray data;
  1557. if (addr.isV4()) {
  1558. uint32_t addr4_data = addr.toUint32();
  1559. data.add(&addr4_data);
  1560. return (deleteLeaseCommon(DELETE_LEASE4, data, *exchange4_));
  1561. } else {
  1562. std::string text_buffer = addr.toText();
  1563. uint32_t addr6_length = text_buffer.size();
  1564. char addr6_buffer[ADDRESS6_TEXT_MAX_LEN + 1];
  1565. if (addr6_length >= sizeof(addr6_buffer)) {
  1566. isc_throw(BadValue, "address value is too large: " << text_buffer);
  1567. }
  1568. if (addr6_length) {
  1569. memcpy(addr6_buffer, text_buffer.c_str(), addr6_length);
  1570. }
  1571. addr6_buffer[addr6_length] = '\0';
  1572. data.add(addr6_buffer);
  1573. return (deleteLeaseCommon(DELETE_LEASE6, data, *exchange6_));
  1574. }
  1575. }
  1576. uint64_t
  1577. CqlLeaseMgr::deleteExpiredReclaimedLeases4(const uint32_t secs) {
  1578. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  1579. DHCPSRV_CQL_DELETE_EXPIRED_RECLAIMED4)
  1580. .arg(secs);
  1581. return (deleteExpiredReclaimedLeasesCommon(secs, DELETE_LEASE4_STATE_EXPIRED));
  1582. }
  1583. uint64_t
  1584. CqlLeaseMgr::deleteExpiredReclaimedLeases6(const uint32_t secs) {
  1585. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  1586. DHCPSRV_CQL_DELETE_EXPIRED_RECLAIMED6)
  1587. .arg(secs);
  1588. return (deleteExpiredReclaimedLeasesCommon(secs, DELETE_LEASE6_STATE_EXPIRED));
  1589. }
  1590. uint64_t
  1591. CqlLeaseMgr::deleteExpiredReclaimedLeasesCommon(const uint32_t secs,
  1592. StatementIndex statement_index) {
  1593. // Set up the WHERE clause value
  1594. CqlDataArray data;
  1595. uint32_t result = 0;
  1596. // State is reclaimed.
  1597. uint32_t state = Lease::STATE_EXPIRED_RECLAIMED;
  1598. data.add(&state);
  1599. // Expiration timestamp.
  1600. uint64_t expiration = static_cast<int64_t>(time(NULL) -
  1601. static_cast<time_t>(secs));
  1602. data.add(&expiration);
  1603. // Get the data
  1604. Lease4Collection result4Leases;
  1605. Lease6Collection result6Leases;
  1606. switch (statement_index) {
  1607. case DELETE_LEASE4_STATE_EXPIRED:
  1608. getLeaseCollection(statement_index, data, result4Leases);
  1609. break;
  1610. case DELETE_LEASE6_STATE_EXPIRED:
  1611. getLeaseCollection(statement_index, data, result6Leases);
  1612. break;
  1613. default:
  1614. break;
  1615. }
  1616. for (Lease4Collection::iterator it = result4Leases.begin();
  1617. it != result4Leases.end(); ++it) {
  1618. if (deleteLease((*it)->addr_)) {
  1619. result++;
  1620. }
  1621. }
  1622. for (Lease6Collection::iterator it = result6Leases.begin();
  1623. it != result6Leases.end(); ++it) {
  1624. if (deleteLease((*it)->addr_)) {
  1625. result++;
  1626. }
  1627. }
  1628. return (result);
  1629. }
  1630. std::string
  1631. CqlLeaseMgr::getName() const {
  1632. std::string name = "";
  1633. try {
  1634. name = dbconn_.getParameter("name");
  1635. } catch (...) {
  1636. // Return an empty name
  1637. }
  1638. return (name);
  1639. }
  1640. std::string
  1641. CqlLeaseMgr::getDescription() const {
  1642. return std::string("Cassandra Database");
  1643. }
  1644. pair<uint32_t, uint32_t>
  1645. CqlLeaseMgr::getVersion() const {
  1646. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  1647. DHCPSRV_CQL_GET_VERSION);
  1648. uint32_t version;
  1649. uint32_t minor;
  1650. CassError rc;
  1651. CassStatement* statement = NULL;
  1652. CassFuture* future = NULL;
  1653. statement = cass_prepared_bind(dbconn_.statements_[GET_VERSION]);
  1654. if (NULL == statement) {
  1655. isc_throw(DbOperationError, "unable to bind statement");
  1656. }
  1657. future = cass_session_execute(dbconn_.session_, statement);
  1658. if (NULL == future) {
  1659. cass_statement_free(statement);
  1660. isc_throw(DbOperationError, "unable to execute statement");
  1661. }
  1662. cass_future_wait(future);
  1663. std::string error;
  1664. dbconn_.checkStatementError(error, future, "unable to GET");
  1665. rc = cass_future_error_code(future);
  1666. if (rc != CASS_OK) {
  1667. cass_future_free(future);
  1668. cass_statement_free(statement);
  1669. isc_throw(DbOperationError, error);
  1670. }
  1671. // Get major and minor versions.
  1672. const CassResult* resultCollection = cass_future_get_result(future);
  1673. CassIterator* rows = cass_iterator_from_result(resultCollection);
  1674. CqlDataArray data;
  1675. CqlDataArray size;
  1676. while (cass_iterator_next(rows)) {
  1677. const CassRow* row = cass_iterator_get_row(rows);
  1678. // version: uint32_t
  1679. data.add(reinterpret_cast<void*>(&version));
  1680. size.add(NULL);
  1681. // minor: uint32_t
  1682. data.add(reinterpret_cast<void*>(&minor));
  1683. size.add(NULL);
  1684. for (size_t i = 0; i < data.size(); i++) {
  1685. CqlLeaseMgr::getData(row, i, data, size, i, *versionExchange_);
  1686. }
  1687. }
  1688. cass_iterator_free(rows);
  1689. cass_result_free(resultCollection);
  1690. cass_future_free(future);
  1691. cass_statement_free(statement);
  1692. return (make_pair(version, minor));
  1693. }
  1694. void
  1695. CqlLeaseMgr::commit() {
  1696. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_COMMIT);
  1697. }
  1698. void
  1699. CqlLeaseMgr::rollback() {
  1700. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_ROLLBACK);
  1701. }
  1702. }; // end of isc::dhcp namespace
  1703. }; // end of isc namespace