cql_lease_mgr.cc 66 KB

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