Kea 2.0.1
mysql_lease_mgr.cc
Go to the documentation of this file.
1// Copyright (C) 2012-2021 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8
10#include <dhcp/duid.h>
11#include <dhcp/hwaddr.h>
13#include <dhcpsrv/cfgmgr.h>
14#include <dhcpsrv/dhcpsrv_log.h>
17#include <dhcpsrv/timer_mgr.h>
20
21#include <boost/array.hpp>
22#include <boost/make_shared.hpp>
23#include <boost/static_assert.hpp>
24#include <mysqld_error.h>
25
26#include <iostream>
27#include <iomanip>
28#include <limits>
29#include <sstream>
30#include <string>
31#include <time.h>
32
33using namespace isc;
34using namespace isc::asiolink;
35using namespace isc::db;
36using namespace isc::dhcp;
37using namespace isc::data;
38using namespace isc::util;
39using namespace std;
40
82
83namespace {
84
89const size_t HOSTNAME_MAX_LEN = 255;
90
95const size_t ADDRESS6_TEXT_MAX_LEN = 39;
96
98const size_t USER_CONTEXT_MAX_LEN = 8192;
99
100boost::array<TaggedStatement, MySqlLeaseMgr::NUM_STATEMENTS>
101tagged_statements = { {
102 {MySqlLeaseMgr::DELETE_LEASE4,
103 "DELETE FROM lease4 WHERE address = ? AND expire = ?"},
104 {MySqlLeaseMgr::DELETE_LEASE4_STATE_EXPIRED,
105 "DELETE FROM lease4 "
106 "WHERE state = ? AND expire < ?"},
107 {MySqlLeaseMgr::DELETE_LEASE6,
108 "DELETE FROM lease6 WHERE address = ? AND expire = ?"},
109 {MySqlLeaseMgr::DELETE_LEASE6_STATE_EXPIRED,
110 "DELETE FROM lease6 "
111 "WHERE state = ? AND expire < ?"},
112 {MySqlLeaseMgr::GET_LEASE4,
113 "SELECT address, hwaddr, client_id, "
114 "valid_lifetime, expire, subnet_id, "
115 "fqdn_fwd, fqdn_rev, hostname, "
116 "state, user_context "
117 "FROM lease4"},
118 {MySqlLeaseMgr::GET_LEASE4_ADDR,
119 "SELECT address, hwaddr, client_id, "
120 "valid_lifetime, expire, subnet_id, "
121 "fqdn_fwd, fqdn_rev, hostname, "
122 "state, user_context "
123 "FROM lease4 "
124 "WHERE address = ?"},
125 {MySqlLeaseMgr::GET_LEASE4_CLIENTID,
126 "SELECT address, hwaddr, client_id, "
127 "valid_lifetime, expire, subnet_id, "
128 "fqdn_fwd, fqdn_rev, hostname, "
129 "state, user_context "
130 "FROM lease4 "
131 "WHERE client_id = ?"},
132 {MySqlLeaseMgr::GET_LEASE4_CLIENTID_SUBID,
133 "SELECT address, hwaddr, client_id, "
134 "valid_lifetime, expire, subnet_id, "
135 "fqdn_fwd, fqdn_rev, hostname, "
136 "state, user_context "
137 "FROM lease4 "
138 "WHERE client_id = ? AND subnet_id = ?"},
139 {MySqlLeaseMgr::GET_LEASE4_HWADDR,
140 "SELECT address, hwaddr, client_id, "
141 "valid_lifetime, expire, subnet_id, "
142 "fqdn_fwd, fqdn_rev, hostname, "
143 "state, user_context "
144 "FROM lease4 "
145 "WHERE hwaddr = ?"},
146 {MySqlLeaseMgr::GET_LEASE4_HWADDR_SUBID,
147 "SELECT address, hwaddr, client_id, "
148 "valid_lifetime, expire, subnet_id, "
149 "fqdn_fwd, fqdn_rev, hostname, "
150 "state, user_context "
151 "FROM lease4 "
152 "WHERE hwaddr = ? AND subnet_id = ?"},
153 {MySqlLeaseMgr::GET_LEASE4_PAGE,
154 "SELECT address, hwaddr, client_id, "
155 "valid_lifetime, expire, subnet_id, "
156 "fqdn_fwd, fqdn_rev, hostname, "
157 "state, user_context "
158 "FROM lease4 "
159 "WHERE address > ? "
160 "ORDER BY address "
161 "LIMIT ?"},
162 {MySqlLeaseMgr::GET_LEASE4_SUBID,
163 "SELECT address, hwaddr, client_id, "
164 "valid_lifetime, expire, subnet_id, "
165 "fqdn_fwd, fqdn_rev, hostname, "
166 "state, user_context "
167 "FROM lease4 "
168 "WHERE subnet_id = ?"},
169 {MySqlLeaseMgr::GET_LEASE4_HOSTNAME,
170 "SELECT address, hwaddr, client_id, "
171 "valid_lifetime, expire, subnet_id, "
172 "fqdn_fwd, fqdn_rev, hostname, "
173 "state, user_context "
174 "FROM lease4 "
175 "WHERE hostname = ?"},
176 {MySqlLeaseMgr::GET_LEASE4_EXPIRE,
177 "SELECT address, hwaddr, client_id, "
178 "valid_lifetime, expire, subnet_id, "
179 "fqdn_fwd, fqdn_rev, hostname, "
180 "state, user_context "
181 "FROM lease4 "
182 "WHERE state != ? "
183 "AND valid_lifetime != 4294967295 "
184 "AND expire < ? "
185 "ORDER BY expire ASC "
186 "LIMIT ?"},
187 {MySqlLeaseMgr::GET_LEASE6,
188 "SELECT address, duid, valid_lifetime, "
189 "expire, subnet_id, pref_lifetime, "
190 "lease_type, iaid, prefix_len, "
191 "fqdn_fwd, fqdn_rev, hostname, "
192 "hwaddr, hwtype, hwaddr_source, "
193 "state, user_context "
194 "FROM lease6"},
195 {MySqlLeaseMgr::GET_LEASE6_ADDR,
196 "SELECT address, duid, valid_lifetime, "
197 "expire, subnet_id, pref_lifetime, "
198 "lease_type, iaid, prefix_len, "
199 "fqdn_fwd, fqdn_rev, hostname, "
200 "hwaddr, hwtype, hwaddr_source, "
201 "state, user_context "
202 "FROM lease6 "
203 "WHERE address = ? AND lease_type = ?"},
204 {MySqlLeaseMgr::GET_LEASE6_DUID_IAID,
205 "SELECT address, duid, valid_lifetime, "
206 "expire, subnet_id, pref_lifetime, "
207 "lease_type, iaid, prefix_len, "
208 "fqdn_fwd, fqdn_rev, hostname, "
209 "hwaddr, hwtype, hwaddr_source, "
210 "state, user_context "
211 "FROM lease6 "
212 "WHERE duid = ? AND iaid = ? AND lease_type = ?"},
213 {MySqlLeaseMgr::GET_LEASE6_DUID_IAID_SUBID,
214 "SELECT address, duid, valid_lifetime, "
215 "expire, subnet_id, pref_lifetime, "
216 "lease_type, iaid, prefix_len, "
217 "fqdn_fwd, fqdn_rev, hostname, "
218 "hwaddr, hwtype, hwaddr_source, "
219 "state, user_context "
220 "FROM lease6 "
221 "WHERE duid = ? AND iaid = ? AND subnet_id = ? "
222 "AND lease_type = ?"},
223 {MySqlLeaseMgr::GET_LEASE6_PAGE,
224 "SELECT address, duid, valid_lifetime, "
225 "expire, subnet_id, pref_lifetime, "
226 "lease_type, iaid, prefix_len, "
227 "fqdn_fwd, fqdn_rev, hostname, "
228 "hwaddr, hwtype, hwaddr_source, "
229 "state, user_context "
230 "FROM lease6 "
231 "WHERE address > ? "
232 "ORDER BY address "
233 "LIMIT ?"},
234 {MySqlLeaseMgr::GET_LEASE6_SUBID,
235 "SELECT address, duid, valid_lifetime, "
236 "expire, subnet_id, pref_lifetime, "
237 "lease_type, iaid, prefix_len, "
238 "fqdn_fwd, fqdn_rev, hostname, "
239 "hwaddr, hwtype, hwaddr_source, "
240 "state, user_context "
241 "FROM lease6 "
242 "WHERE subnet_id = ?"},
243 {MySqlLeaseMgr::GET_LEASE6_DUID,
244 "SELECT address, duid, valid_lifetime, "
245 "expire, subnet_id, pref_lifetime, "
246 "lease_type, iaid, prefix_len, "
247 "fqdn_fwd, fqdn_rev, hostname, "
248 "hwaddr, hwtype, hwaddr_source, "
249 "state, user_context "
250 "FROM lease6 "
251 "WHERE duid = ?"},
252 {MySqlLeaseMgr::GET_LEASE6_HOSTNAME,
253 "SELECT address, duid, valid_lifetime, "
254 "expire, subnet_id, pref_lifetime, "
255 "lease_type, iaid, prefix_len, "
256 "fqdn_fwd, fqdn_rev, hostname, "
257 "hwaddr, hwtype, hwaddr_source, "
258 "state, user_context "
259 "FROM lease6 "
260 "WHERE hostname = ?"},
261 {MySqlLeaseMgr::GET_LEASE6_EXPIRE,
262 "SELECT address, duid, valid_lifetime, "
263 "expire, subnet_id, pref_lifetime, "
264 "lease_type, iaid, prefix_len, "
265 "fqdn_fwd, fqdn_rev, hostname, "
266 "hwaddr, hwtype, hwaddr_source, "
267 "state, user_context "
268 "FROM lease6 "
269 "WHERE state != ? "
270 "AND valid_lifetime != 4294967295 "
271 "AND expire < ? "
272 "ORDER BY expire ASC "
273 "LIMIT ?"},
274 {MySqlLeaseMgr::INSERT_LEASE4,
275 "INSERT INTO lease4(address, hwaddr, client_id, "
276 "valid_lifetime, expire, subnet_id, "
277 "fqdn_fwd, fqdn_rev, hostname, "
278 "state, user_context) "
279 "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"},
280 {MySqlLeaseMgr::INSERT_LEASE6,
281 "INSERT INTO lease6(address, duid, valid_lifetime, "
282 "expire, subnet_id, pref_lifetime, "
283 "lease_type, iaid, prefix_len, "
284 "fqdn_fwd, fqdn_rev, hostname, "
285 "hwaddr, hwtype, hwaddr_source, "
286 "state, user_context) "
287 "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"},
288 {MySqlLeaseMgr::UPDATE_LEASE4,
289 "UPDATE lease4 SET address = ?, hwaddr = ?, "
290 "client_id = ?, valid_lifetime = ?, expire = ?, "
291 "subnet_id = ?, fqdn_fwd = ?, fqdn_rev = ?, "
292 "hostname = ?, "
293 "state = ?, user_context = ? "
294 "WHERE address = ? AND expire = ?"},
295 {MySqlLeaseMgr::UPDATE_LEASE6,
296 "UPDATE lease6 SET address = ?, duid = ?, "
297 "valid_lifetime = ?, expire = ?, subnet_id = ?, "
298 "pref_lifetime = ?, lease_type = ?, iaid = ?, "
299 "prefix_len = ?, fqdn_fwd = ?, fqdn_rev = ?, "
300 "hostname = ?, hwaddr = ?, hwtype = ?, hwaddr_source = ?, "
301 "state = ?, user_context = ? "
302 "WHERE address = ? AND expire = ?"},
303 {MySqlLeaseMgr::ALL_LEASE4_STATS,
304 "SELECT subnet_id, state, leases as state_count "
305 "FROM lease4_stat ORDER BY subnet_id, state"},
306 {MySqlLeaseMgr::SUBNET_LEASE4_STATS,
307 "SELECT subnet_id, state, leases as state_count "
308 "FROM lease4_stat "
309 "WHERE subnet_id = ? "
310 "ORDER BY state"},
311 {MySqlLeaseMgr::SUBNET_RANGE_LEASE4_STATS,
312 "SELECT subnet_id, state, leases as state_count "
313 "FROM lease4_stat "
314 "WHERE subnet_id >= ? and subnet_id <= ? "
315 "ORDER BY subnet_id, state"},
316 {MySqlLeaseMgr::ALL_LEASE6_STATS,
317 "SELECT subnet_id, lease_type, state, leases as state_count "
318 "FROM lease6_stat ORDER BY subnet_id, lease_type, state"},
319 {MySqlLeaseMgr::SUBNET_LEASE6_STATS,
320 "SELECT subnet_id, lease_type, state, leases as state_count "
321 "FROM lease6_stat "
322 "WHERE subnet_id = ? "
323 "ORDER BY lease_type, state"},
324 {MySqlLeaseMgr::SUBNET_RANGE_LEASE6_STATS,
325 "SELECT subnet_id, lease_type, state, leases as state_count "
326 "FROM lease6_stat "
327 "WHERE subnet_id >= ? and subnet_id <= ? "
328 "ORDER BY subnet_id, lease_type, state"}
329 }
330};
331
332} // namespace
333
334namespace isc {
335namespace dhcp {
336
343
345public:
346
358 static void setErrorIndicators(MYSQL_BIND* bind, my_bool* error,
359 size_t count) {
360 for (size_t i = 0; i < count; ++i) {
361 error[i] = MLM_FALSE;
362 bind[i].error = reinterpret_cast<my_bool*>(&error[i]);
363 }
364 }
365
379 static std::string getColumnsInError(my_bool* error, std::string* names,
380 size_t count) {
381 std::string result = "";
382
383 // Accumulate list of column names
384 for (size_t i = 0; i < count; ++i) {
385 if (error[i] == MLM_TRUE) {
386 if (!result.empty()) {
387 result += ", ";
388 }
389 result += names[i];
390 }
391 }
392
393 if (result.empty()) {
394 result = "(None)";
395 }
396
397 return (result);
398 }
399};
400
413
416 static const size_t LEASE_COLUMNS = 11;
417
418public:
419
424 MySqlLease4Exchange() : addr4_(0), hwaddr_length_(0), hwaddr_null_(MLM_FALSE),
425 client_id_length_(0), client_id_null_(MLM_FALSE),
426 subnet_id_(0), valid_lifetime_(0),
427 fqdn_fwd_(false), fqdn_rev_(false), hostname_length_(0),
428 state_(0), user_context_length_(0),
429 user_context_null_(MLM_FALSE) {
430 memset(hwaddr_buffer_, 0, sizeof(hwaddr_buffer_));
431 memset(client_id_buffer_, 0, sizeof(client_id_buffer_));
432 memset(hostname_buffer_, 0, sizeof(hostname_buffer_));
433 memset(user_context_, 0, sizeof(user_context_));
434 std::fill(&error_[0], &error_[LEASE_COLUMNS], MLM_FALSE);
435
436 // Set the column names (for error messages)
437 columns_[0] = "address";
438 columns_[1] = "hwaddr";
439 columns_[2] = "client_id";
440 columns_[3] = "valid_lifetime";
441 columns_[4] = "expire";
442 columns_[5] = "subnet_id";
443 columns_[6] = "fqdn_fwd";
444 columns_[7] = "fqdn_rev";
445 columns_[8] = "hostname";
446 columns_[9] = "state";
447 columns_[10] = "user_context";
448 BOOST_STATIC_ASSERT(10 < LEASE_COLUMNS);
449 }
450
460 std::vector<MYSQL_BIND> createBindForSend(const Lease4Ptr& lease) {
461
462 // Store lease object to ensure it remains valid.
463 lease_ = lease;
464
465 // Initialize prior to constructing the array of MYSQL_BIND structures.
466 // It sets all fields, including is_null, to zero, so we need to set
467 // is_null only if it should be true. This gives up minor performance
468 // benefit while being safe approach. For improved readability, the
469 // code that explicitly sets is_null is there, but is commented out.
470 memset(bind_, 0, sizeof(bind_));
471
472 // Set up the structures for the various components of the lease4
473 // structure.
474
475 try {
476 // address: uint32_t
477 // The address in the Lease structure is an IOAddress object. Convert
478 // this to an integer for storage.
479 addr4_ = lease_->addr_.toUint32();
480 bind_[0].buffer_type = MYSQL_TYPE_LONG;
481 bind_[0].buffer = reinterpret_cast<char*>(&addr4_);
482 bind_[0].is_unsigned = MLM_TRUE;
483 // bind_[0].is_null = &MLM_FALSE; // commented out for performance
484 // reasons, see memset() above
485
486 // hwaddr: varbinary(20) - hardware/MAC address
487 HWAddrPtr hwaddr = lease_->hwaddr_;
488 if (hwaddr) {
489 hwaddr_ = hwaddr->hwaddr_;
490 hwaddr_length_ = hwaddr->hwaddr_.size();
491
492 // Make sure that the buffer has at least length of 1, even if
493 // empty HW address is passed. This is required by some of the
494 // MySQL connectors that the buffer is set to non-null value.
495 // Otherwise, null value would be inserted into the database,
496 // rather than empty string.
497 if (hwaddr_.empty()) {
498 hwaddr_.resize(1);
499 }
500
501 bind_[1].buffer_type = MYSQL_TYPE_BLOB;
502 bind_[1].buffer = reinterpret_cast<char*>(&(hwaddr_[0]));
503 bind_[1].buffer_length = hwaddr_length_;
504 bind_[1].length = &hwaddr_length_;
505 } else {
506 bind_[1].buffer_type = MYSQL_TYPE_NULL;
507 // According to http://dev.mysql.com/doc/refman/5.5/en/
508 // c-api-prepared-statement-data-structures.html, the other
509 // fields doesn't matter if type is set to MYSQL_TYPE_NULL,
510 // but let's set them to some sane values in case earlier versions
511 // didn't have that assumption.
512 hwaddr_null_ = MLM_TRUE;
513 bind_[1].buffer = NULL;
514 bind_[1].is_null = &hwaddr_null_;
515 }
516
517 // client_id: varbinary(128)
518 if (lease_->client_id_) {
519 client_id_ = lease_->client_id_->getClientId();
520 client_id_length_ = client_id_.size();
521
522 // Make sure that the buffer has at least length of 1, even if
523 // empty client id is passed. This is required by some of the
524 // MySQL connectors that the buffer is set to non-null value.
525 // Otherwise, null value would be inserted into the database,
526 // rather than empty string.
527 if (client_id_.empty()) {
528 client_id_.resize(1);
529 }
530
531 bind_[2].buffer_type = MYSQL_TYPE_BLOB;
532 bind_[2].buffer = reinterpret_cast<char*>(&client_id_[0]);
533 bind_[2].buffer_length = client_id_length_;
534 bind_[2].length = &client_id_length_;
535 // bind_[2].is_null = &MLM_FALSE; // commented out for performance
536 // reasons, see memset() above
537 } else {
538 bind_[2].buffer_type = MYSQL_TYPE_NULL;
539 // According to http://dev.mysql.com/doc/refman/5.5/en/
540 // c-api-prepared-statement-data-structures.html, the other
541 // fields doesn't matter if type is set to MYSQL_TYPE_NULL,
542 // but let's set them to some sane values in case earlier versions
543 // didn't have that assumption.
544 client_id_null_ = MLM_TRUE;
545 bind_[2].buffer = NULL;
546 bind_[2].is_null = &client_id_null_;
547 }
548
549 // valid lifetime: unsigned int
550 bind_[3].buffer_type = MYSQL_TYPE_LONG;
551 bind_[3].buffer = reinterpret_cast<char*>(&lease_->valid_lft_);
552 bind_[3].is_unsigned = MLM_TRUE;
553 // bind_[3].is_null = &MLM_FALSE; // commented out for performance
554 // reasons, see memset() above
555
556 // expire: timestamp
557 // The lease structure holds the client last transmission time (cltt_)
558 // For convenience for external tools, this is converted to lease
559 // expiry time (expire). The relationship is given by:
560 //
561 // expire = cltt_ + valid_lft_
562 // Avoid overflow
563 uint32_t valid_lft = lease_->valid_lft_;
564 if (valid_lft == Lease::INFINITY_LFT) {
565 valid_lft = 0;
566 }
567 MySqlConnection::convertToDatabaseTime(lease_->cltt_, valid_lft,
568 expire_);
569 bind_[4].buffer_type = MYSQL_TYPE_TIMESTAMP;
570 bind_[4].buffer = reinterpret_cast<char*>(&expire_);
571 bind_[4].buffer_length = sizeof(expire_);
572 // bind_[4].is_null = &MLM_FALSE; // commented out for performance
573 // reasons, see memset() above
574
575 // subnet_id: unsigned int
576 // Can use lease_->subnet_id_ directly as it is of type uint32_t.
577 bind_[5].buffer_type = MYSQL_TYPE_LONG;
578 bind_[5].buffer = reinterpret_cast<char*>(&lease_->subnet_id_);
579 bind_[5].is_unsigned = MLM_TRUE;
580 // bind_[5].is_null = &MLM_FALSE; // commented out for performance
581 // reasons, see memset() above
582
583 // fqdn_fwd: boolean
584 bind_[6].buffer_type = MYSQL_TYPE_TINY;
585 bind_[6].buffer = reinterpret_cast<char*>(&lease_->fqdn_fwd_);
586 bind_[6].is_unsigned = MLM_TRUE;
587 // bind_[6].is_null = &MLM_FALSE; // commented out for performance
588 // reasons, see memset() above
589
590 // fqdn_rev: boolean
591 bind_[7].buffer_type = MYSQL_TYPE_TINY;
592 bind_[7].buffer = reinterpret_cast<char*>(&lease_->fqdn_rev_);
593 bind_[7].is_unsigned = MLM_TRUE;
594 // bind_[7].is_null = &MLM_FALSE; // commented out for performance
595 // reasons, see memset() above
596
597 // hostname: varchar(255)
598 // Note that previously we used MYSQL_TYPE_VARCHAR instead of
599 // MYSQL_TYPE_STRING. However, that caused 'buffer type not supported'
600 // errors on some systems running MariaDB.
601 bind_[8].buffer_type = MYSQL_TYPE_STRING;
602 bind_[8].buffer = const_cast<char*>(lease_->hostname_.c_str());
603 bind_[8].buffer_length = lease_->hostname_.length();
604 // bind_[8].is_null = &MLM_FALSE; // commented out for performance
605 // reasons, see memset() above
606
607 // state: uint32_t
608 bind_[9].buffer_type = MYSQL_TYPE_LONG;
609 bind_[9].buffer = reinterpret_cast<char*>(&lease_->state_);
610 bind_[9].is_unsigned = MLM_TRUE;
611 // bind_[9].is_null = &MLM_FALSE; // commented out for performance
612 // reasons, see memset() above
613
614 // user_context: text
615 ConstElementPtr ctx = lease->getContext();
616 if (ctx) {
617 bind_[10].buffer_type = MYSQL_TYPE_STRING;
618 std::string ctx_txt = ctx->str();
619 strncpy(user_context_, ctx_txt.c_str(), USER_CONTEXT_MAX_LEN - 1);
620 bind_[10].buffer = user_context_;
621 bind_[10].buffer_length = ctx_txt.length();
622 // bind_[10].is_null = &MLM_FALSE; // commented out for performance
623 // reasons, see memset() above
624 } else {
625 bind_[10].buffer_type = MYSQL_TYPE_NULL;
626 }
627
628 // Add the error flags
629 setErrorIndicators(bind_, error_, LEASE_COLUMNS);
630
631 // .. and check that we have the numbers correct at compile time.
632 BOOST_STATIC_ASSERT(10 < LEASE_COLUMNS);
633
634 } catch (const std::exception& ex) {
636 "Could not create bind array from Lease4: "
637 << lease_->addr_.toText() << ", reason: " << ex.what());
638 }
639
640 // Add the data to the vector. Note the end element is one after the
641 // end of the array.
642 return (std::vector<MYSQL_BIND>(&bind_[0], &bind_[LEASE_COLUMNS]));
643 }
644
650 std::vector<MYSQL_BIND> createBindForReceive() {
651
652 // Initialize MYSQL_BIND array.
653 // It sets all fields, including is_null, to zero, so we need to set
654 // is_null only if it should be true. This gives up minor performance
655 // benefit while being safe approach. For improved readability, the
656 // code that explicitly sets is_null is there, but is commented out.
657 memset(bind_, 0, sizeof(bind_));
658
659 // address: uint32_t
660 bind_[0].buffer_type = MYSQL_TYPE_LONG;
661 bind_[0].buffer = reinterpret_cast<char*>(&addr4_);
662 bind_[0].is_unsigned = MLM_TRUE;
663 // bind_[0].is_null = &MLM_FALSE; // commented out for performance
664 // reasons, see memset() above
665
666 // hwaddr: varbinary(20)
667 hwaddr_length_ = sizeof(hwaddr_buffer_);
668 bind_[1].buffer_type = MYSQL_TYPE_BLOB;
669 bind_[1].buffer = reinterpret_cast<char*>(hwaddr_buffer_);
670 bind_[1].buffer_length = hwaddr_length_;
671 bind_[1].length = &hwaddr_length_;
672 // bind_[1].is_null = &MLM_FALSE; // commented out for performance
673 // reasons, see memset() above
674
675 // client_id: varbinary(128)
676 client_id_length_ = sizeof(client_id_buffer_);
677 bind_[2].buffer_type = MYSQL_TYPE_BLOB;
678 bind_[2].buffer = reinterpret_cast<char*>(client_id_buffer_);
679 bind_[2].buffer_length = client_id_length_;
680 bind_[2].length = &client_id_length_;
681 bind_[2].is_null = &client_id_null_;
682 // bind_[2].is_null = &MLM_FALSE; // commented out for performance
683 // reasons, see memset() above
684
685 // valid lifetime: unsigned int
686 bind_[3].buffer_type = MYSQL_TYPE_LONG;
687 bind_[3].buffer = reinterpret_cast<char*>(&valid_lifetime_);
688 bind_[3].is_unsigned = MLM_TRUE;
689 // bind_[3].is_null = &MLM_FALSE; // commented out for performance
690 // reasons, see memset() above
691
692 // expire: timestamp
693 bind_[4].buffer_type = MYSQL_TYPE_TIMESTAMP;
694 bind_[4].buffer = reinterpret_cast<char*>(&expire_);
695 bind_[4].buffer_length = sizeof(expire_);
696 // bind_[4].is_null = &MLM_FALSE; // commented out for performance
697 // reasons, see memset() above
698
699 // subnet_id: unsigned int
700 bind_[5].buffer_type = MYSQL_TYPE_LONG;
701 bind_[5].buffer = reinterpret_cast<char*>(&subnet_id_);
702 bind_[5].is_unsigned = MLM_TRUE;
703 // bind_[5].is_null = &MLM_FALSE; // commented out for performance
704 // reasons, see memset() above
705
706 // fqdn_fwd: boolean
707 bind_[6].buffer_type = MYSQL_TYPE_TINY;
708 bind_[6].buffer = reinterpret_cast<char*>(&fqdn_fwd_);
709 bind_[6].is_unsigned = MLM_TRUE;
710 // bind_[6].is_null = &MLM_FALSE; // commented out for performance
711 // reasons, see memset() above
712
713 // fqdn_rev: boolean
714 bind_[7].buffer_type = MYSQL_TYPE_TINY;
715 bind_[7].buffer = reinterpret_cast<char*>(&fqdn_rev_);
716 bind_[7].is_unsigned = MLM_TRUE;
717 // bind_[7].is_null = &MLM_FALSE; // commented out for performance
718 // reasons, see memset() above
719
720 // hostname: varchar(255)
721 // Note that previously we used MYSQL_TYPE_VARCHAR instead of
722 // MYSQL_TYPE_STRING. However, that caused 'buffer type not supported'
723 // errors on some systems running MariaDB.
724 hostname_length_ = sizeof(hostname_buffer_);
725 bind_[8].buffer_type = MYSQL_TYPE_STRING;
726 bind_[8].buffer = reinterpret_cast<char*>(hostname_buffer_);
727 bind_[8].buffer_length = hostname_length_;
728 bind_[8].length = &hostname_length_;
729 // bind_[8].is_null = &MLM_FALSE; // commented out for performance
730 // reasons, see memset() above
731
732 // state: uint32_t
733 bind_[9].buffer_type = MYSQL_TYPE_LONG;
734 bind_[9].buffer = reinterpret_cast<char*>(&state_);
735 bind_[9].is_unsigned = MLM_TRUE;
736 // bind_[9].is_null = &MLM_FALSE; // commented out for performance
737 // reasons, see memset() above
738
739 // user_context: text
740 user_context_null_ = MLM_FALSE;
741 user_context_length_ = sizeof(user_context_);
742 bind_[10].buffer_type = MYSQL_TYPE_STRING;
743 bind_[10].buffer = reinterpret_cast<char*>(user_context_);
744 bind_[10].buffer_length = user_context_length_;
745 bind_[10].length = &user_context_length_;
746 bind_[10].is_null = &user_context_null_;
747
748 // Add the error flags
749 setErrorIndicators(bind_, error_, LEASE_COLUMNS);
750
751 // .. and check that we have the numbers correct at compile time.
752 BOOST_STATIC_ASSERT(10 < LEASE_COLUMNS);
753
754 // Add the data to the vector. Note the end element is one after the
755 // end of the array.
756 return (std::vector<MYSQL_BIND>(&bind_[0], &bind_[LEASE_COLUMNS]));
757 }
758
768 // Convert times received from the database to times for the lease
769 // structure
770 time_t cltt = 0;
771 // Recover from overflow
772 uint32_t valid_lft = valid_lifetime_;
773 if (valid_lft == Lease::INFINITY_LFT) {
774 valid_lft = 0;
775 }
776 MySqlConnection::convertFromDatabaseTime(expire_, valid_lft, cltt);
777
778 if (client_id_null_ == MLM_TRUE) {
779 // There's no client-id, so we pass client-id_length_ set to 0
780 client_id_length_ = 0;
781 }
782
783 // Hostname is passed to Lease4 as a string object. We have to create
784 // it from the buffer holding hostname and the buffer length.
785 std::string hostname(hostname_buffer_,
786 hostname_buffer_ + hostname_length_);
787
788 // Set hardware address if it was set
789 HWAddrPtr hwaddr;
790 if (hwaddr_null_ == MLM_FALSE) {
791 hwaddr.reset(new HWAddr(hwaddr_buffer_, hwaddr_length_, HTYPE_ETHER));
792 }
793
794 // Convert user_context to string as well.
795 std::string user_context;
796 if (user_context_null_ == MLM_FALSE) {
797 user_context_[user_context_length_] = '\0';
798 user_context.assign(user_context_);
799 }
800
801 // Set the user context if there is one.
802 ConstElementPtr ctx;
803 if (!user_context.empty()) {
804 ctx = Element::fromJSON(user_context);
805 if (!ctx || (ctx->getType() != Element::map)) {
806 isc_throw(BadValue, "user context '" << user_context
807 << "' is not a JSON map");
808 }
809 }
810
811 Lease4Ptr lease(boost::make_shared<Lease4>(addr4_, hwaddr,
812 client_id_buffer_,
813 client_id_length_,
814 valid_lifetime_, cltt,
815 subnet_id_, fqdn_fwd_,
816 fqdn_rev_, hostname));
817
818 // Set state.
819 lease->state_ = state_;
820
821 if (ctx) {
822 lease->setContext(ctx);
823 }
824
825 return (lease);
826 }
827
838 std::string getErrorColumns() {
839 return (getColumnsInError(error_, columns_, LEASE_COLUMNS));
840 }
841
842private:
843
844 // Note: All array lengths are equal to the corresponding variable in the
845 // schema.
846 // Note: Arrays are declared fixed length for speed of creation
847 uint32_t addr4_;
848 MYSQL_BIND bind_[LEASE_COLUMNS];
849 std::string columns_[LEASE_COLUMNS];
850 my_bool error_[LEASE_COLUMNS];
851 Lease4Ptr lease_;
852 std::vector<uint8_t> hwaddr_;
853 uint8_t hwaddr_buffer_[HWAddr::MAX_HWADDR_LEN];
854 unsigned long hwaddr_length_;
855 my_bool hwaddr_null_;
856 std::vector<uint8_t> client_id_;
857 uint8_t client_id_buffer_[ClientId::MAX_CLIENT_ID_LEN];
858 unsigned long client_id_length_;
859 my_bool client_id_null_;
860 MYSQL_TIME expire_;
861 uint32_t subnet_id_;
862 uint32_t valid_lifetime_;
863 my_bool fqdn_fwd_;
864 my_bool fqdn_rev_;
865 char hostname_buffer_[HOSTNAME_MAX_LEN];
866 unsigned long hostname_length_;
867 uint32_t state_;
868 char user_context_[USER_CONTEXT_MAX_LEN];
869 unsigned long user_context_length_;
870 my_bool user_context_null_;
871};
872
885
888 static const size_t LEASE_COLUMNS = 17;
889
890public:
891
896 MySqlLease6Exchange() : addr6_length_(0), hwaddr_length_(0),
897 hwaddr_null_(MLM_FALSE), duid_length_(0),
898 iaid_(0), lease_type_(0), prefix_len_(0),
899 pref_lifetime_(0), subnet_id_(0), valid_lifetime_(0),
900 fqdn_fwd_(false), fqdn_rev_(false),
901 hostname_length_(0), hwtype_(0), hwaddr_source_(0),
902 state_(0), user_context_length_(0),
903 user_context_null_(MLM_FALSE) {
904 memset(addr6_buffer_, 0, sizeof(addr6_buffer_));
905 memset(duid_buffer_, 0, sizeof(duid_buffer_));
906 memset(hostname_buffer_, 0, sizeof(hostname_buffer_));
907 memset(hwaddr_buffer_, 0, sizeof(hwaddr_buffer_));
908 memset(user_context_, 0, sizeof(user_context_));
909 std::fill(&error_[0], &error_[LEASE_COLUMNS], MLM_FALSE);
910
911 // Set the column names (for error messages)
912 columns_[0] = "address";
913 columns_[1] = "duid";
914 columns_[2] = "valid_lifetime";
915 columns_[3] = "expire";
916 columns_[4] = "subnet_id";
917 columns_[5] = "pref_lifetime";
918 columns_[6] = "lease_type";
919 columns_[7] = "iaid";
920 columns_[8] = "prefix_len";
921 columns_[9] = "fqdn_fwd";
922 columns_[10] = "fqdn_rev";
923 columns_[11] = "hostname";
924 columns_[12] = "hwaddr";
925 columns_[13] = "hwtype";
926 columns_[14] = "hwaddr_source";
927 columns_[15] = "state";
928 columns_[16] = "user_context";
929 BOOST_STATIC_ASSERT(16 < LEASE_COLUMNS);
930 }
931
940 std::vector<MYSQL_BIND> createBindForSend(const Lease6Ptr& lease) {
941 // Store lease object to ensure it remains valid.
942 lease_ = lease;
943
944 // Ensure bind_ array clear for constructing the MYSQL_BIND structures
945 // for this lease.
946 // It sets all fields, including is_null, to zero, so we need to set
947 // is_null only if it should be true. This gives up minor performance
948 // benefit while being safe approach. For improved readability, the
949 // code that explicitly sets is_null is there, but is commented out.
950 memset(bind_, 0, sizeof(bind_));
951
952 try {
953 // address: varchar(39)
954 addr6_ = lease_->addr_.toText();
955 addr6_length_ = addr6_.size();
956
957 // In the following statement, the string is being read. However, the
958 // MySQL C interface does not use "const", so the "buffer" element
959 // is declared as "char*" instead of "const char*". To resolve this,
960 // the "const" is discarded. (Note that the address of addr6_.c_str()
961 // is guaranteed to be valid until the next non-const operation on
962 // addr6_.)
963 //
964 // The const_cast could be avoided by copying the string to a writable
965 // buffer and storing the address of that in the "buffer" element.
966 // However, this introduces a copy operation (with additional overhead)
967 // purely to get round the structures introduced by design of the
968 // MySQL interface (which uses the area pointed to by "buffer" as input
969 // when specifying query parameters and as output when retrieving data).
970 // For that reason, "const_cast" has been used.
971 bind_[0].buffer_type = MYSQL_TYPE_STRING;
972 bind_[0].buffer = const_cast<char*>(addr6_.c_str());
973 bind_[0].buffer_length = addr6_length_;
974 bind_[0].length = &addr6_length_;
975 // bind_[0].is_null = &MLM_FALSE; // commented out for performance
976 // reasons, see memset() above
977
978 // duid: varchar(128)
979 if (!lease_->duid_) {
980 isc_throw(DbOperationError, "lease6 for address " << addr6_
981 << " is missing mandatory client-id.");
982 }
983 duid_ = lease_->duid_->getDuid();
984 duid_length_ = duid_.size();
985
986 bind_[1].buffer_type = MYSQL_TYPE_BLOB;
987 bind_[1].buffer = reinterpret_cast<char*>(&(duid_[0]));
988 bind_[1].buffer_length = duid_length_;
989 bind_[1].length = &duid_length_;
990 // bind_[1].is_null = &MLM_FALSE; // commented out for performance
991 // reasons, see memset() above
992
993 // valid lifetime: unsigned int
994 bind_[2].buffer_type = MYSQL_TYPE_LONG;
995 bind_[2].buffer = reinterpret_cast<char*>(&lease_->valid_lft_);
996 bind_[2].is_unsigned = MLM_TRUE;
997 // bind_[2].is_null = &MLM_FALSE; // commented out for performance
998 // reasons, see memset() above
999
1000 // expire: timestamp
1001 // The lease structure holds the client last transmission time (cltt_)
1002 // For convenience for external tools, this is converted to lease
1003 // expiry time (expire). The relationship is given by:
1004 //
1005 // expire = cltt_ + valid_lft_
1006 // Avoid overflow
1007 uint32_t valid_lft = lease_->valid_lft_;
1008 if (valid_lft == Lease::INFINITY_LFT) {
1009 valid_lft = 0;
1010 }
1011 MySqlConnection::convertToDatabaseTime(lease_->cltt_, valid_lft,
1012 expire_);
1013 bind_[3].buffer_type = MYSQL_TYPE_TIMESTAMP;
1014 bind_[3].buffer = reinterpret_cast<char*>(&expire_);
1015 bind_[3].buffer_length = sizeof(expire_);
1016 // bind_[3].is_null = &MLM_FALSE; // commented out for performance
1017 // reasons, see memset() above
1018
1019 // subnet_id: unsigned int
1020 // Can use lease_->subnet_id_ directly as it is of type uint32_t.
1021 bind_[4].buffer_type = MYSQL_TYPE_LONG;
1022 bind_[4].buffer = reinterpret_cast<char*>(&lease_->subnet_id_);
1023 bind_[4].is_unsigned = MLM_TRUE;
1024 // bind_[4].is_null = &MLM_FALSE; // commented out for performance
1025 // reasons, see memset() above
1026
1027 // pref_lifetime: unsigned int
1028 // Can use lease_->preferred_lft_ directly as it is of type uint32_t.
1029 bind_[5].buffer_type = MYSQL_TYPE_LONG;
1030 bind_[5].buffer = reinterpret_cast<char*>(&lease_->preferred_lft_);
1031 bind_[5].is_unsigned = MLM_TRUE;
1032 // bind_[5].is_null = &MLM_FALSE; // commented out for performance
1033 // reasons, see memset() above
1034
1035 // lease_type: tinyint
1036 // Must convert to uint8_t as lease_->type_ is a LeaseType variable.
1037 lease_type_ = lease_->type_;
1038 bind_[6].buffer_type = MYSQL_TYPE_TINY;
1039 bind_[6].buffer = reinterpret_cast<char*>(&lease_type_);
1040 bind_[6].is_unsigned = MLM_TRUE;
1041 // bind_[6].is_null = &MLM_FALSE; // commented out for performance
1042 // reasons, see memset() above
1043
1044 // iaid: unsigned int
1045 // Can use lease_->iaid_ directly as it is of type uint32_t.
1046 bind_[7].buffer_type = MYSQL_TYPE_LONG;
1047 bind_[7].buffer = reinterpret_cast<char*>(&lease_->iaid_);
1048 bind_[7].is_unsigned = MLM_TRUE;
1049 // bind_[7].is_null = &MLM_FALSE; // commented out for performance
1050 // reasons, see memset() above
1051
1052 // prefix_len: unsigned tinyint
1053 // Can use lease_->prefixlen_ directly as it is uint32_t.
1054 bind_[8].buffer_type = MYSQL_TYPE_TINY;
1055 bind_[8].buffer = reinterpret_cast<char*>(&lease_->prefixlen_);
1056 bind_[8].is_unsigned = MLM_TRUE;
1057 // bind_[8].is_null = &MLM_FALSE; // commented out for performance
1058 // reasons, see memset() above
1059
1060 // fqdn_fwd: boolean
1061 bind_[9].buffer_type = MYSQL_TYPE_TINY;
1062 bind_[9].buffer = reinterpret_cast<char*>(&lease_->fqdn_fwd_);
1063 bind_[9].is_unsigned = MLM_TRUE;
1064 // bind_[7].is_null = &MLM_FALSE; // commented out for performance
1065 // reasons, see memset() above
1066
1067 // fqdn_rev: boolean
1068 bind_[10].buffer_type = MYSQL_TYPE_TINY;
1069 bind_[10].buffer = reinterpret_cast<char*>(&lease_->fqdn_rev_);
1070 bind_[10].is_unsigned = MLM_TRUE;
1071 // bind_[10].is_null = &MLM_FALSE; // commented out for performance
1072 // reasons, see memset() above
1073
1074 // hostname: varchar(255)
1075 bind_[11].buffer_type = MYSQL_TYPE_STRING;
1076 bind_[11].buffer = const_cast<char*>(lease_->hostname_.c_str());
1077 bind_[11].buffer_length = lease_->hostname_.length();
1078 // bind_[11].is_null = &MLM_FALSE; // commented out for performance
1079 // reasons, see memset() above
1080
1081 // hwaddr: varbinary(20) - hardware/MAC address
1082 HWAddrPtr hwaddr = lease_->hwaddr_;
1083 if (hwaddr) {
1084 hwaddr_ = hwaddr->hwaddr_;
1085 hwaddr_length_ = hwaddr->hwaddr_.size();
1086
1087 // Make sure that the buffer has at least length of 1, even if
1088 // empty HW address is passed. This is required by some of the
1089 // MySQL connectors that the buffer is set to non-null value.
1090 // Otherwise, null value would be inserted into the database,
1091 // rather than empty string.
1092 if (hwaddr_.empty()) {
1093 hwaddr_.resize(1);
1094 }
1095
1096 bind_[12].buffer_type = MYSQL_TYPE_BLOB;
1097 bind_[12].buffer = reinterpret_cast<char*>(&(hwaddr_[0]));
1098 bind_[12].buffer_length = hwaddr_length_;
1099 bind_[12].length = &hwaddr_length_;
1100 } else {
1101 bind_[12].buffer_type = MYSQL_TYPE_NULL;
1102 // According to http://dev.mysql.com/doc/refman/5.5/en/
1103 // c-api-prepared-statement-data-structures.html, the other
1104 // fields doesn't matter if type is set to MYSQL_TYPE_NULL,
1105 // but let's set them to some sane values in case earlier versions
1106 // didn't have that assumption.
1107 hwaddr_null_ = MLM_TRUE;
1108 bind_[12].buffer = NULL;
1109 bind_[12].is_null = &hwaddr_null_;
1110 }
1111
1112 // hardware type: unsigned short int (16 bits)
1113 if (hwaddr) {
1114 hwtype_ = lease->hwaddr_->htype_;
1115 bind_[13].buffer_type = MYSQL_TYPE_SHORT;
1116 bind_[13].buffer = reinterpret_cast<char*>(&hwtype_);
1117 bind_[13].is_unsigned = MLM_TRUE;
1118 } else {
1119 hwtype_ = 0;
1120 bind_[13].buffer_type = MYSQL_TYPE_NULL;
1121 // According to http://dev.mysql.com/doc/refman/5.5/en/
1122 // c-api-prepared-statement-data-structures.html, the other
1123 // fields doesn't matter if type is set to MYSQL_TYPE_NULL,
1124 // but let's set them to some sane values in case earlier versions
1125 // didn't have that assumption.
1126 hwaddr_null_ = MLM_TRUE;
1127 bind_[13].buffer = NULL;
1128 bind_[13].is_null = &hwaddr_null_;
1129 }
1130
1131 // hardware source: unsigned int (32 bits)
1132 if (hwaddr) {
1133 hwaddr_source_ = lease->hwaddr_->source_;
1134 bind_[14].buffer_type = MYSQL_TYPE_LONG;
1135 bind_[14].buffer = reinterpret_cast<char*>(&hwaddr_source_);
1136 bind_[14].is_unsigned = MLM_TRUE;
1137 } else {
1138 hwaddr_source_ = 0;
1139 bind_[14].buffer_type = MYSQL_TYPE_NULL;
1140 // According to http://dev.mysql.com/doc/refman/5.5/en/
1141 // c-api-prepared-statement-data-structures.html, the other
1142 // fields doesn't matter if type is set to MYSQL_TYPE_NULL,
1143 // but let's set them to some sane values in case earlier versions
1144 // didn't have that assumption.
1145 hwaddr_null_ = MLM_TRUE;
1146 bind_[14].buffer = NULL;
1147 bind_[14].is_null = &hwaddr_null_;
1148 }
1149
1150 // state: uint32_t
1151 bind_[15].buffer_type = MYSQL_TYPE_LONG;
1152 bind_[15].buffer = reinterpret_cast<char*>(&lease_->state_);
1153 bind_[15].is_unsigned = MLM_TRUE;
1154 // bind_[15].is_null = &MLM_FALSE; // commented out for performance
1155 // reasons, see memset() above
1156
1157 // user_context: text
1158 ConstElementPtr ctx = lease->getContext();
1159 if (ctx) {
1160 bind_[16].buffer_type = MYSQL_TYPE_STRING;
1161 std::string ctx_txt = ctx->str();
1162 strncpy(user_context_, ctx_txt.c_str(), USER_CONTEXT_MAX_LEN - 1);
1163 bind_[16].buffer = user_context_;
1164 bind_[16].buffer_length = ctx_txt.length();
1165 // bind_[16].is_null = &MLM_FALSE; // commented out for performance
1166 // reasons, see memset() above
1167 } else {
1168 bind_[16].buffer_type = MYSQL_TYPE_NULL;
1169 }
1170
1171 // Add the error flags
1172 setErrorIndicators(bind_, error_, LEASE_COLUMNS);
1173
1174 // .. and check that we have the numbers correct at compile time.
1175 BOOST_STATIC_ASSERT(16 < LEASE_COLUMNS);
1176
1177 } catch (const std::exception& ex) {
1179 "Could not create bind array from Lease6: "
1180 << lease_->addr_.toText() << ", reason: " << ex.what());
1181 }
1182
1183 // Add the data to the vector. Note the end element is one after the
1184 // end of the array.
1185 return (std::vector<MYSQL_BIND>(&bind_[0], &bind_[LEASE_COLUMNS]));
1186 }
1187
1196 std::vector<MYSQL_BIND> createBindForReceive() {
1197
1198 // Initialize MYSQL_BIND array.
1199 // It sets all fields, including is_null, to zero, so we need to set
1200 // is_null only if it should be true. This gives up minor performance
1201 // benefit while being safe approach. For improved readability, the
1202 // code that explicitly sets is_null is there, but is commented out.
1203 memset(bind_, 0, sizeof(bind_));
1204
1205 // address: varchar(39)
1206 // A Lease6_ address has a maximum of 39 characters. The array is
1207 // one byte longer than this to guarantee that we can always null
1208 // terminate it whatever is returned.
1209 addr6_length_ = sizeof(addr6_buffer_) - 1;
1210 bind_[0].buffer_type = MYSQL_TYPE_STRING;
1211 bind_[0].buffer = addr6_buffer_;
1212 bind_[0].buffer_length = addr6_length_;
1213 bind_[0].length = &addr6_length_;
1214 // bind_[0].is_null = &MLM_FALSE; // commented out for performance
1215 // reasons, see memset() above
1216
1217 // client_id: varbinary(128)
1218 duid_length_ = sizeof(duid_buffer_);
1219 bind_[1].buffer_type = MYSQL_TYPE_BLOB;
1220 bind_[1].buffer = reinterpret_cast<char*>(duid_buffer_);
1221 bind_[1].buffer_length = duid_length_;
1222 bind_[1].length = &duid_length_;
1223 // bind_[1].is_null = &MLM_FALSE; // commented out for performance
1224 // reasons, see memset() above
1225
1226 // valid lifetime: unsigned int
1227 bind_[2].buffer_type = MYSQL_TYPE_LONG;
1228 bind_[2].buffer = reinterpret_cast<char*>(&valid_lifetime_);
1229 bind_[2].is_unsigned = MLM_TRUE;
1230 // bind_[2].is_null = &MLM_FALSE; // commented out for performance
1231 // reasons, see memset() above
1232
1233 // expire: timestamp
1234 bind_[3].buffer_type = MYSQL_TYPE_TIMESTAMP;
1235 bind_[3].buffer = reinterpret_cast<char*>(&expire_);
1236 bind_[3].buffer_length = sizeof(expire_);
1237 // bind_[3].is_null = &MLM_FALSE; // commented out for performance
1238 // reasons, see memset() above
1239
1240 // subnet_id: unsigned int
1241 bind_[4].buffer_type = MYSQL_TYPE_LONG;
1242 bind_[4].buffer = reinterpret_cast<char*>(&subnet_id_);
1243 bind_[4].is_unsigned = MLM_TRUE;
1244 // bind_[4].is_null = &MLM_FALSE; // commented out for performance
1245 // reasons, see memset() above
1246
1247 // pref_lifetime: unsigned int
1248 bind_[5].buffer_type = MYSQL_TYPE_LONG;
1249 bind_[5].buffer = reinterpret_cast<char*>(&pref_lifetime_);
1250 bind_[5].is_unsigned = MLM_TRUE;
1251 // bind_[5].is_null = &MLM_FALSE; // commented out for performance
1252 // reasons, see memset() above
1253
1254 // lease_type: tinyint
1255 bind_[6].buffer_type = MYSQL_TYPE_TINY;
1256 bind_[6].buffer = reinterpret_cast<char*>(&lease_type_);
1257 bind_[6].is_unsigned = MLM_TRUE;
1258 // bind_[6].is_null = &MLM_FALSE; // commented out for performance
1259 // reasons, see memset() above
1260
1261 // iaid: unsigned int
1262 bind_[7].buffer_type = MYSQL_TYPE_LONG;
1263 bind_[7].buffer = reinterpret_cast<char*>(&iaid_);
1264 bind_[7].is_unsigned = MLM_TRUE;
1265 // bind_[7].is_null = &MLM_FALSE; // commented out for performance
1266 // reasons, see memset() above
1267
1268 // prefix_len: unsigned tinyint
1269 bind_[8].buffer_type = MYSQL_TYPE_TINY;
1270 bind_[8].buffer = reinterpret_cast<char*>(&prefix_len_);
1271 bind_[8].is_unsigned = MLM_TRUE;
1272 // bind_[8].is_null = &MLM_FALSE; // commented out for performance
1273 // reasons, see memset() above
1274
1275 // fqdn_fwd: boolean
1276 bind_[9].buffer_type = MYSQL_TYPE_TINY;
1277 bind_[9].buffer = reinterpret_cast<char*>(&fqdn_fwd_);
1278 bind_[9].is_unsigned = MLM_TRUE;
1279 // bind_[9].is_null = &MLM_FALSE; // commented out for performance
1280 // reasons, see memset() above
1281
1282 // fqdn_rev: boolean
1283 bind_[10].buffer_type = MYSQL_TYPE_TINY;
1284 bind_[10].buffer = reinterpret_cast<char*>(&fqdn_rev_);
1285 bind_[10].is_unsigned = MLM_TRUE;
1286 // bind_[10].is_null = &MLM_FALSE; // commented out for performance
1287 // reasons, see memset() above
1288
1289 // hostname: varchar(255)
1290 hostname_length_ = sizeof(hostname_buffer_);
1291 bind_[11].buffer_type = MYSQL_TYPE_STRING;
1292 bind_[11].buffer = reinterpret_cast<char*>(hostname_buffer_);
1293 bind_[11].buffer_length = hostname_length_;
1294 bind_[11].length = &hostname_length_;
1295 // bind_[11].is_null = &MLM_FALSE; // commented out for performance
1296 // reasons, see memset() above
1297
1298 // hwaddr: varbinary(20)
1299 hwaddr_null_ = MLM_FALSE;
1300 hwaddr_length_ = sizeof(hwaddr_buffer_);
1301 bind_[12].buffer_type = MYSQL_TYPE_BLOB;
1302 bind_[12].buffer = reinterpret_cast<char*>(hwaddr_buffer_);
1303 bind_[12].buffer_length = hwaddr_length_;
1304 bind_[12].length = &hwaddr_length_;
1305 bind_[12].is_null = &hwaddr_null_;
1306
1307 // hardware type: unsigned short int (16 bits)
1308 bind_[13].buffer_type = MYSQL_TYPE_SHORT;
1309 bind_[13].buffer = reinterpret_cast<char*>(&hwtype_);
1310 bind_[13].is_unsigned = MLM_TRUE;
1311
1312 // hardware source: unsigned int (32 bits)
1313 bind_[14].buffer_type = MYSQL_TYPE_LONG;
1314 bind_[14].buffer = reinterpret_cast<char*>(&hwaddr_source_);
1315 bind_[14].is_unsigned = MLM_TRUE;
1316
1317 // state: uint32_t
1318 bind_[15].buffer_type = MYSQL_TYPE_LONG;
1319 bind_[15].buffer = reinterpret_cast<char*>(&state_);
1320 bind_[15].is_unsigned = MLM_TRUE;
1321 // bind_[15].is_null = &MLM_FALSE; // commented out for performance
1322 // reasons, see memset() above
1323
1324 // user_context: text
1325 user_context_null_ = MLM_FALSE;
1326 user_context_length_ = sizeof(user_context_);
1327 bind_[16].buffer_type = MYSQL_TYPE_STRING;
1328 bind_[16].buffer = reinterpret_cast<char*>(user_context_);
1329 bind_[16].buffer_length = user_context_length_;
1330 bind_[16].length = &user_context_length_;
1331 bind_[16].is_null = &user_context_null_;
1332
1333 // Add the error flags
1334 setErrorIndicators(bind_, error_, LEASE_COLUMNS);
1335
1336 // .. and check that we have the numbers correct at compile time.
1337 BOOST_STATIC_ASSERT(16 < LEASE_COLUMNS);
1338
1339 // Add the data to the vector. Note the end element is one after the
1340 // end of the array.
1341 return (std::vector<MYSQL_BIND>(&bind_[0], &bind_[LEASE_COLUMNS]));
1342 }
1343
1355 // The address buffer is declared larger than the buffer size passed
1356 // to the access function so that we can always append a null byte.
1357 // Create the IOAddress object corresponding to the received data.
1358 addr6_buffer_[addr6_length_] = '\0';
1359 std::string address = addr6_buffer_;
1360 IOAddress addr(address);
1361
1362 // Set the lease type in a variable of the appropriate data type, which
1363 // has been initialized with an arbitrary (but valid) value.
1365 switch (lease_type_) {
1366 case Lease::TYPE_NA:
1367 type = Lease::TYPE_NA;
1368 break;
1369
1370 case Lease::TYPE_TA:
1371 type = Lease::TYPE_TA;
1372 break;
1373
1374 case Lease::TYPE_PD:
1375 type = Lease::TYPE_PD;
1376 break;
1377
1378 default:
1379 isc_throw(BadValue, "invalid lease type returned (" <<
1380 static_cast<int>(lease_type_) << ") for lease with "
1381 << "address " << address << ". Only 0, 1, or 2 are "
1382 << "allowed.");
1383 }
1384
1385 // Set up DUID,
1386 DuidPtr duid_ptr(new DUID(duid_buffer_, duid_length_));
1387
1388 // Hostname is passed to Lease6 as a string object, so we have to
1389 // create it from the hostname buffer and length.
1390 std::string hostname(hostname_buffer_,
1391 hostname_buffer_ + hostname_length_);
1392
1393 // Set hardware address if it was set
1394 HWAddrPtr hwaddr;
1395 if (hwaddr_null_ == MLM_FALSE) {
1396 hwaddr.reset(new HWAddr(hwaddr_buffer_, hwaddr_length_, hwtype_));
1397 hwaddr->source_ = hwaddr_source_;
1398 }
1399
1400 // Convert user_context to string as well.
1401 std::string user_context;
1402 if (user_context_null_ == MLM_FALSE) {
1403 user_context_[user_context_length_] = '\0';
1404 user_context.assign(user_context_);
1405 }
1406
1407 // Set the user context if there is one.
1408 ConstElementPtr ctx;
1409 if (!user_context.empty()) {
1410 ctx = Element::fromJSON(user_context);
1411 if (!ctx || (ctx->getType() != Element::map)) {
1412 isc_throw(BadValue, "user context '" << user_context
1413 << "' is not a JSON map");
1414 }
1415 }
1416
1417 // Create the lease and set the cltt (after converting from the
1418 // expire time retrieved from the database).
1419 Lease6Ptr result(boost::make_shared<Lease6>(type, addr, duid_ptr, iaid_,
1420 pref_lifetime_,
1421 valid_lifetime_, subnet_id_,
1422 fqdn_fwd_, fqdn_rev_,
1423 hostname, hwaddr,
1424 prefix_len_));
1425 time_t cltt = 0;
1426 // Recover from overflow
1427 uint32_t valid_lft = valid_lifetime_;
1428 if (valid_lft == Lease::INFINITY_LFT) {
1429 valid_lft = 0;
1430 }
1431 MySqlConnection::convertFromDatabaseTime(expire_, valid_lft, cltt);
1432 // Update cltt_ and current_cltt_ explicitly.
1433 result->cltt_ = cltt;
1434 result->current_cltt_ = cltt;
1435
1436 // Set state.
1437 result->state_ = state_;
1438
1439 if (ctx) {
1440 result->setContext(ctx);
1441 }
1442
1443 return (result);
1444 }
1445
1456 std::string getErrorColumns() {
1457 return (getColumnsInError(error_, columns_, LEASE_COLUMNS));
1458 }
1459
1460private:
1461
1462 // Note: All array lengths are equal to the corresponding variable in the
1463 // schema.
1464 // Note: arrays are declared fixed length for speed of creation
1465 std::string addr6_;
1466 char addr6_buffer_[ADDRESS6_TEXT_MAX_LEN + 1];
1467 unsigned long addr6_length_;
1468 MYSQL_BIND bind_[LEASE_COLUMNS];
1469 std::string columns_[LEASE_COLUMNS];
1470 my_bool error_[LEASE_COLUMNS];
1471 Lease6Ptr lease_;
1472 std::vector<uint8_t> hwaddr_;
1473 uint8_t hwaddr_buffer_[HWAddr::MAX_HWADDR_LEN];
1474 unsigned long hwaddr_length_;
1475 my_bool hwaddr_null_;
1476 std::vector<uint8_t> duid_;
1477 uint8_t duid_buffer_[DUID::MAX_DUID_LEN];
1478 unsigned long duid_length_;
1479 MYSQL_TIME expire_;
1480 uint32_t iaid_;
1481 uint8_t lease_type_;
1482 uint8_t prefix_len_;
1483 uint32_t pref_lifetime_;
1484 uint32_t subnet_id_;
1485 uint32_t valid_lifetime_;
1486 my_bool fqdn_fwd_;
1487 my_bool fqdn_rev_;
1488 char hostname_buffer_[HOSTNAME_MAX_LEN];
1489 unsigned long hostname_length_;
1490 uint16_t hwtype_;
1491 uint32_t hwaddr_source_;
1492 uint32_t state_;
1493 char user_context_[USER_CONTEXT_MAX_LEN];
1494 unsigned long user_context_length_;
1495 my_bool user_context_null_;
1496};
1497
1504
1506public:
1507
1516 MySqlLeaseStatsQuery(MySqlConnection& conn, const size_t statement_index,
1517 const bool fetch_type)
1518 : conn_(conn), statement_index_(statement_index), statement_(NULL),
1519 fetch_type_(fetch_type),
1520 // Set the number of columns in the bind array based on fetch_type
1521 // This is the number of columns expected in the result set
1522 bind_(fetch_type_ ? 4 : 3),
1523 subnet_id_(0), lease_type_(0), state_(0), state_count_(0) {
1524 validateStatement();
1525 }
1526
1536 MySqlLeaseStatsQuery(MySqlConnection& conn, const size_t statement_index,
1537 const bool fetch_type, const SubnetID& subnet_id)
1538 : LeaseStatsQuery(subnet_id), conn_(conn), statement_index_(statement_index),
1539 statement_(NULL), fetch_type_(fetch_type),
1540 // Set the number of columns in the bind array based on fetch_type
1541 // This is the number of columns expected in the result set
1542 bind_(fetch_type_ ? 4 : 3),
1543 subnet_id_(0), lease_type_(0), state_(0), state_count_(0) {
1544 validateStatement();
1545 }
1546
1559 MySqlLeaseStatsQuery(MySqlConnection& conn, const size_t statement_index,
1560 const bool fetch_type, const SubnetID& first_subnet_id,
1561 const SubnetID& last_subnet_id)
1562 : LeaseStatsQuery(first_subnet_id, last_subnet_id), conn_(conn),
1563 statement_index_(statement_index), statement_(NULL), fetch_type_(fetch_type),
1564 // Set the number of columns in the bind array based on fetch_type
1565 // This is the number of columns expected in the result set
1566 bind_(fetch_type_ ? 4 : 3),
1567 subnet_id_(0), lease_type_(0), state_(0), state_count_(0) {
1568 validateStatement();
1569 }
1570
1573 (void) mysql_stmt_free_result(statement_);
1574 }
1575
1583 void start() {
1584 // Set up where clause inputs if needed.
1585 if (getSelectMode() != ALL_SUBNETS) {
1586 MYSQL_BIND inbind[2];
1587 memset(inbind, 0, sizeof(inbind));
1588
1589 // Add first_subnet_id used by both single and range.
1590 inbind[0].buffer_type = MYSQL_TYPE_LONG;
1591 inbind[0].buffer = reinterpret_cast<char*>(&first_subnet_id_);
1592 inbind[0].is_unsigned = MLM_TRUE;
1593
1594 // Add last_subnet_id for range.
1595 if (getSelectMode() == SUBNET_RANGE) {
1596 inbind[1].buffer_type = MYSQL_TYPE_LONG;
1597 inbind[1].buffer = reinterpret_cast<char*>(&last_subnet_id_);
1598 inbind[1].is_unsigned = MLM_TRUE;
1599 }
1600
1601 // Bind the parameters to the statement
1602 int status = mysql_stmt_bind_param(statement_, &inbind[0]);
1603 conn_.checkError(status, statement_index_, "unable to bind parameters");
1604 }
1605
1606 int col = 0;
1607 // subnet_id: unsigned int
1608 bind_[col].buffer_type = MYSQL_TYPE_LONG;
1609 bind_[col].buffer = reinterpret_cast<char*>(&subnet_id_);
1610 bind_[col].is_unsigned = MLM_TRUE;
1611 ++col;
1612
1613 // Fetch the lease type if we were told to do so.
1614 if (fetch_type_) {
1615 // lease type: uint32_t
1616 bind_[col].buffer_type = MYSQL_TYPE_LONG;
1617 bind_[col].buffer = reinterpret_cast<char*>(&lease_type_);
1618 bind_[col].is_unsigned = MLM_TRUE;
1619 ++col;
1620 } else {
1621 fetch_type_ = Lease::TYPE_NA;
1622 }
1623
1624 // state: uint32_t
1625 bind_[col].buffer_type = MYSQL_TYPE_LONG;
1626 bind_[col].buffer = reinterpret_cast<char*>(&state_);
1627 bind_[col].is_unsigned = MLM_TRUE;
1628 ++col;
1629
1630 // state_count_: int64_t
1631 bind_[col].buffer_type = MYSQL_TYPE_LONGLONG;
1632 bind_[col].buffer = reinterpret_cast<char*>(&state_count_);
1633 //bind_[col].is_unsigned = MLM_FALSE;
1634
1635 // Set up the MYSQL_BIND array for the data being returned
1636 // and bind it to the statement.
1637 int status = mysql_stmt_bind_result(statement_, &bind_[0]);
1638 conn_.checkError(status, statement_index_, "outbound binding failed");
1639
1640 // Execute the statement
1641 status = MysqlExecuteStatement(statement_);
1642 conn_.checkError(status, statement_index_, "unable to execute");
1643
1644 // Ensure that all the lease information is retrieved in one go to avoid
1645 // overhead of going back and forth between client and server.
1646 status = mysql_stmt_store_result(statement_);
1647 conn_.checkError(status, statement_index_, "results storage failed");
1648 }
1649
1666 bool have_row = false;
1667 int status = mysql_stmt_fetch(statement_);
1668 if (status == MLM_MYSQL_FETCH_SUCCESS) {
1669 row.subnet_id_ = static_cast<SubnetID>(subnet_id_);
1670 row.lease_type_ = static_cast<Lease::Type>(lease_type_);
1671 row.lease_state_ = state_;
1672 if (state_count_ >= 0) {
1673 row.state_count_ = state_count_;
1674 } else {
1675 row.state_count_ = 0;
1676 if (!negative_count_) {
1677 negative_count_ = true;
1679 }
1680 }
1681 have_row = true;
1682 } else if (status != MYSQL_NO_DATA) {
1683 conn_.checkError(status, statement_index_, "getNextRow failed");
1684 }
1685
1686 return (have_row);
1687 }
1688
1689private:
1690
1694 void validateStatement() {
1695 if (statement_index_ >= MySqlLeaseMgr::NUM_STATEMENTS) {
1696 isc_throw(BadValue, "MySqlLeaseStatsQuery"
1697 " - invalid statement index" << statement_index_);
1698 }
1699
1700 statement_ = conn_.statements_[statement_index_];
1701 }
1702
1704 MySqlConnection& conn_;
1705
1707 size_t statement_index_;
1708
1710 MYSQL_STMT *statement_;
1711
1713 bool fetch_type_;
1714
1716 std::vector<MYSQL_BIND> bind_;
1717
1719 uint32_t subnet_id_;
1720
1722 uint32_t lease_type_;
1723
1725 uint32_t state_;
1726
1728 int64_t state_count_;
1729
1731 static bool negative_count_;
1732};
1733
1734// Initialize negative state count flag to false.
1735bool MySqlLeaseStatsQuery::negative_count_ = false;
1736
1737// MySqlLeaseContext Constructor
1738
1740 IOServiceAccessorPtr io_service_accessor,
1741 DbCallback db_reconnect_callback)
1742 : conn_(parameters, io_service_accessor, db_reconnect_callback) {
1743}
1744
1745// MySqlLeaseContextAlloc Constructor and Destructor
1746
1747MySqlLeaseMgr::MySqlLeaseContextAlloc::MySqlLeaseContextAlloc(
1748 const MySqlLeaseMgr& mgr) : ctx_(), mgr_(mgr) {
1749
1750 if (MultiThreadingMgr::instance().getMode()) {
1751 // multi-threaded
1752 {
1753 // we need to protect the whole pool_ operation, hence extra scope {}
1754 lock_guard<mutex> lock(mgr_.pool_->mutex_);
1755 if (!mgr_.pool_->pool_.empty()) {
1756 ctx_ = mgr_.pool_->pool_.back();
1757 mgr_.pool_->pool_.pop_back();
1758 }
1759 }
1760 if (!ctx_) {
1761 ctx_ = mgr_.createContext();
1762 }
1763 } else {
1764 // single-threaded
1765 if (mgr_.pool_->pool_.empty()) {
1766 isc_throw(Unexpected, "No available MySQL lease context?!");
1767 }
1768 ctx_ = mgr_.pool_->pool_.back();
1769 }
1770}
1771
1772MySqlLeaseMgr::MySqlLeaseContextAlloc::~MySqlLeaseContextAlloc() {
1773 if (MultiThreadingMgr::instance().getMode()) {
1774 // multi-threaded
1775 lock_guard<mutex> lock(mgr_.pool_->mutex_);
1776 mgr_.pool_->pool_.push_back(ctx_);
1777 }
1778 // If running in single-threaded mode, there's nothing to do here.
1779}
1780
1781// MySqlLeaseMgr Constructor and Destructor
1782
1784 : parameters_(parameters), timer_name_("") {
1785
1786 // Create unique timer name per instance.
1787 timer_name_ = "MySqlLeaseMgr[";
1788 timer_name_ += boost::lexical_cast<std::string>(reinterpret_cast<uint64_t>(this));
1789 timer_name_ += "]DbReconnectTimer";
1790
1791 // Validate schema version first.
1792 std::pair<uint32_t, uint32_t> code_version(MYSQL_SCHEMA_VERSION_MAJOR,
1794 std::pair<uint32_t, uint32_t> db_version = getVersion();
1795 if (code_version != db_version) {
1797 "MySQL schema version mismatch: need version: "
1798 << code_version.first << "." << code_version.second
1799 << " found version: " << db_version.first << "."
1800 << db_version.second);
1801 }
1802
1803 // Create an initial context.
1804 pool_.reset(new MySqlLeaseContextPool());
1805 pool_->pool_.push_back(createContext());
1806}
1807
1809}
1810
1811bool
1814
1815 // Invoke application layer connection lost callback.
1816 if (!DatabaseConnection::invokeDbLostCallback(db_reconnect_ctl)) {
1817 return (false);
1818 }
1819
1820 bool reopened = false;
1821
1822 const std::string timer_name = db_reconnect_ctl->timerName();
1823
1824 // At least one connection was lost.
1825 try {
1826 CfgDbAccessPtr cfg_db = CfgMgr::instance().getCurrentCfg()->getCfgDbAccess();
1828 LeaseMgrFactory::create(cfg_db->getLeaseDbAccessString());
1829 reopened = true;
1830 } catch (const std::exception& ex) {
1832 .arg(ex.what());
1833 }
1834
1835 if (reopened) {
1836 // Cancel the timer.
1837 if (TimerMgr::instance()->isTimerRegistered(timer_name)) {
1838 TimerMgr::instance()->unregisterTimer(timer_name);
1839 }
1840
1841 // Invoke application layer connection recovered callback.
1842 if (!DatabaseConnection::invokeDbRecoveredCallback(db_reconnect_ctl)) {
1843 return (false);
1844 }
1845 } else {
1846 if (!db_reconnect_ctl->checkRetries()) {
1847 // We're out of retries, log it and initiate shutdown.
1849 .arg(db_reconnect_ctl->maxRetries());
1850
1851 // Cancel the timer.
1852 if (TimerMgr::instance()->isTimerRegistered(timer_name)) {
1853 TimerMgr::instance()->unregisterTimer(timer_name);
1854 }
1855
1856 // Invoke application layer connection failed callback.
1858 return (false);
1859 }
1860
1862 .arg(db_reconnect_ctl->maxRetries() - db_reconnect_ctl->retriesLeft() + 1)
1863 .arg(db_reconnect_ctl->maxRetries())
1864 .arg(db_reconnect_ctl->retryInterval());
1865
1866 // Start the timer.
1867 if (!TimerMgr::instance()->isTimerRegistered(timer_name)) {
1868 TimerMgr::instance()->registerTimer(timer_name,
1869 std::bind(&MySqlLeaseMgr::dbReconnect, db_reconnect_ctl),
1870 db_reconnect_ctl->retryInterval(),
1872 }
1873 TimerMgr::instance()->setup(timer_name);
1874 }
1875
1876 return (true);
1877}
1878
1879// Create context.
1880
1883 MySqlLeaseContextPtr ctx(new MySqlLeaseContext(parameters_,
1886
1887 // Open the database.
1888 ctx->conn_.openDatabase();
1889
1890 // Prepare all statements likely to be used.
1891 ctx->conn_.prepareStatements(tagged_statements.begin(),
1892 tagged_statements.end());
1893
1894 // Create the exchange objects for use in exchanging data between the
1895 // program and the database.
1896 ctx->exchange4_.reset(new MySqlLease4Exchange());
1897 ctx->exchange6_.reset(new MySqlLease6Exchange());
1898
1899 // Create ReconnectCtl for this connection.
1900 ctx->conn_.makeReconnectCtl(timer_name_);
1901
1902 return (ctx);
1903}
1904
1905std::string
1907 std::stringstream tmp;
1908 tmp << "MySQL backend " << MYSQL_SCHEMA_VERSION_MAJOR;
1909 tmp << "." << MYSQL_SCHEMA_VERSION_MINOR;
1910 tmp << ", library " << mysql_get_client_info();
1911 return (tmp.str());
1912}
1913
1914// Add leases to the database. The two public methods accept a lease object
1915// (either V4 of V6), bind the contents to the appropriate prepared
1916// statement, then call common code to execute the statement.
1917
1918bool
1919MySqlLeaseMgr::addLeaseCommon(MySqlLeaseContextPtr& ctx,
1920 StatementIndex stindex,
1921 std::vector<MYSQL_BIND>& bind) {
1922
1923 // Bind the parameters to the statement
1924 int status = mysql_stmt_bind_param(ctx->conn_.statements_[stindex], &bind[0]);
1925 checkError(ctx, status, stindex, "unable to bind parameters");
1926
1927 // Execute the statement
1928 status = MysqlExecuteStatement(ctx->conn_.statements_[stindex]);
1929 if (status != 0) {
1930
1931 // Failure: check for the special case of duplicate entry. If this is
1932 // the case, we return false to indicate that the row was not added.
1933 // Otherwise we throw an exception.
1934 if (mysql_errno(ctx->conn_.mysql_) == ER_DUP_ENTRY) {
1935 return (false);
1936 }
1937 checkError(ctx, status, stindex, "unable to execute");
1938 }
1939
1940 // Insert succeeded
1941 return (true);
1942}
1943
1944bool
1947 .arg(lease->addr_.toText());
1948
1949 // Get a context
1950 MySqlLeaseContextAlloc get_context(*this);
1951 MySqlLeaseContextPtr ctx = get_context.ctx_;
1952
1953 // Create the MYSQL_BIND array for the lease
1954 std::vector<MYSQL_BIND> bind = ctx->exchange4_->createBindForSend(lease);
1955
1956 // ... and drop to common code.
1957 auto result = addLeaseCommon(ctx, INSERT_LEASE4, bind);
1958
1959 // Update lease current expiration time (allows update between the creation
1960 // of the Lease up to the point of insertion in the database).
1961 lease->updateCurrentExpirationTime();
1962
1963 return (result);
1964}
1965
1966bool
1969 .arg(lease->addr_.toText())
1970 .arg(lease->type_);
1971
1972 // Get a context
1973 MySqlLeaseContextAlloc get_context(*this);
1974 MySqlLeaseContextPtr ctx = get_context.ctx_;
1975
1976 // Create the MYSQL_BIND array for the lease
1977 std::vector<MYSQL_BIND> bind = ctx->exchange6_->createBindForSend(lease);
1978
1979 // ... and drop to common code.
1980 auto result = addLeaseCommon(ctx, INSERT_LEASE6, bind);
1981
1982 // Update lease current expiration time (allows update between the creation
1983 // of the Lease up to the point of insertion in the database).
1984 lease->updateCurrentExpirationTime();
1985
1986 return (result);
1987}
1988
1989// Extraction of leases from the database.
1990//
1991// All getLease() methods ultimately call getLeaseCollection(). This
1992// binds the input parameters passed to it with the appropriate prepared
1993// statement and executes the statement. It then gets the results from the
1994// database. getlease() methods that expect a single result back call it
1995// with the "single" parameter set true: this causes an exception to be
1996// generated if multiple records can be retrieved from the result set. (Such
1997// an occurrence either indicates corruption in the database, or that an
1998// assumption that a query can only return a single record is incorrect.)
1999// Methods that require a collection of records have "single" set to the
2000// default value of false. The logic is the same for both Lease4 and Lease6
2001// objects, so the code is templated.
2002//
2003// Methods that require a collection of objects access this method through
2004// two interface methods (also called getLeaseCollection()). These are
2005// short enough as to be defined in the header file: all they do is to supply
2006// the appropriate MySqlLeaseXExchange object depending on the type of the
2007// LeaseCollection objects passed to them.
2008//
2009// Methods that require a single object to be returned access the method
2010// through two interface methods (called getLease()). As well as supplying
2011// the appropriate exchange object, they convert between lease collection
2012// holding zero or one leases into an appropriate Lease object.
2013
2014template <typename Exchange, typename LeaseCollection>
2015void
2016MySqlLeaseMgr::getLeaseCollection(MySqlLeaseContextPtr& ctx,
2017 StatementIndex stindex,
2018 MYSQL_BIND* bind,
2019 Exchange& exchange,
2020 LeaseCollection& result,
2021 bool single) const {
2022 int status;
2023
2024 if (bind) {
2025 // Bind the selection parameters to the statement
2026 status = mysql_stmt_bind_param(ctx->conn_.statements_[stindex], bind);
2027 checkError(ctx, status, stindex, "unable to bind WHERE clause parameter");
2028 }
2029
2030 // Set up the MYSQL_BIND array for the data being returned and bind it to
2031 // the statement.
2032 std::vector<MYSQL_BIND> outbind = exchange->createBindForReceive();
2033 status = mysql_stmt_bind_result(ctx->conn_.statements_[stindex], &outbind[0]);
2034 checkError(ctx, status, stindex, "unable to bind SELECT clause parameters");
2035
2036 // Execute the statement
2037 status = MysqlExecuteStatement(ctx->conn_.statements_[stindex]);
2038 checkError(ctx, status, stindex, "unable to execute");
2039
2040 // Ensure that all the lease information is retrieved in one go to avoid
2041 // overhead of going back and forth between client and server.
2042 status = mysql_stmt_store_result(ctx->conn_.statements_[stindex]);
2043 checkError(ctx, status, stindex, "unable to set up for storing all results");
2044
2045 // Set up the fetch "release" object to release resources associated
2046 // with the call to mysql_stmt_fetch when this method exits, then
2047 // retrieve the data.
2048 MySqlFreeResult fetch_release(ctx->conn_.statements_[stindex]);
2049 int count = 0;
2050 while ((status = mysql_stmt_fetch(ctx->conn_.statements_[stindex])) == 0) {
2051 try {
2052 result.push_back(exchange->getLeaseData());
2053
2054 } catch (const isc::BadValue& ex) {
2055 // Rethrow the exception with a bit more data.
2056 isc_throw(BadValue, ex.what() << ". Statement is <" <<
2057 ctx->conn_.text_statements_[stindex] << ">");
2058 }
2059
2060 if (single && (++count > 1)) {
2061 isc_throw(MultipleRecords, "multiple records were found in the "
2062 "database where only one was expected for query "
2063 << ctx->conn_.text_statements_[stindex]);
2064 }
2065 }
2066
2067 // How did the fetch end?
2068 if (status == 1) {
2069 // Error - unable to fetch results
2070 checkError(ctx, status, stindex, "unable to fetch results");
2071 } else if (status == MYSQL_DATA_TRUNCATED) {
2072 // Data truncated - throw an exception indicating what was at fault
2073 isc_throw(DataTruncated, ctx->conn_.text_statements_[stindex]
2074 << " returned truncated data: columns affected are "
2075 << exchange->getErrorColumns());
2076 }
2077}
2078
2079void
2080MySqlLeaseMgr::getLease(MySqlLeaseContextPtr& ctx,
2081 StatementIndex stindex, MYSQL_BIND* bind,
2082 Lease4Ptr& result) const {
2083 // Create appropriate collection object and get all leases matching
2084 // the selection criteria. The "single" parameter is true to indicate
2085 // that the called method should throw an exception if multiple
2086 // matching records are found: this particular method is called when only
2087 // one or zero matches is expected.
2088 Lease4Collection collection;
2089 getLeaseCollection(ctx, stindex, bind, ctx->exchange4_, collection, true);
2090
2091 // Return single record if present, else clear the lease.
2092 if (collection.empty()) {
2093 result.reset();
2094 } else {
2095 result = *collection.begin();
2096 }
2097}
2098
2099void
2100MySqlLeaseMgr::getLease(MySqlLeaseContextPtr& ctx,
2101 StatementIndex stindex, MYSQL_BIND* bind,
2102 Lease6Ptr& result) const {
2103 // Create appropriate collection object and get all leases matching
2104 // the selection criteria. The "single" parameter is true to indicate
2105 // that the called method should throw an exception if multiple
2106 // matching records are found: this particular method is called when only
2107 // one or zero matches is expected.
2108 Lease6Collection collection;
2109 getLeaseCollection(ctx, stindex, bind, ctx->exchange6_, collection, true);
2110
2111 // Return single record if present, else clear the lease.
2112 if (collection.empty()) {
2113 result.reset();
2114 } else {
2115 result = *collection.begin();
2116 }
2117}
2118
2119// Basic lease access methods. Obtain leases from the database using various
2120// criteria.
2121
2125 .arg(addr.toText());
2126
2127 // Set up the WHERE clause value
2128 MYSQL_BIND inbind[1];
2129 memset(inbind, 0, sizeof(inbind));
2130
2131 uint32_t addr4 = addr.toUint32();
2132 inbind[0].buffer_type = MYSQL_TYPE_LONG;
2133 inbind[0].buffer = reinterpret_cast<char*>(&addr4);
2134 inbind[0].is_unsigned = MLM_TRUE;
2135
2136 // Get the data
2137 Lease4Ptr result;
2138
2139 // Get a context
2140 MySqlLeaseContextAlloc get_context(*this);
2141 MySqlLeaseContextPtr ctx = get_context.ctx_;
2142
2143 getLease(ctx, GET_LEASE4_ADDR, inbind, result);
2144
2145 return (result);
2146}
2147
2149MySqlLeaseMgr::getLease4(const HWAddr& hwaddr) const {
2151 .arg(hwaddr.toText());
2152
2153 // Set up the WHERE clause value
2154 MYSQL_BIND inbind[1];
2155 memset(inbind, 0, sizeof(inbind));
2156
2157 inbind[0].buffer_type = MYSQL_TYPE_BLOB;
2158
2159 unsigned long hwaddr_length = hwaddr.hwaddr_.size();
2160
2161 // If the data happens to be empty, we have to create a 1 byte dummy
2162 // buffer and pass it to the binding.
2163 uint8_t single_byte_data = 0;
2164
2165 // As "buffer" is "char*" - even though the data is being read - we need
2166 // to cast away the "const"ness as well as reinterpreting the data as
2167 // a "char*". (We could avoid the "const_cast" by copying the data to a
2168 // local variable, but as the data is only being read, this introduces
2169 // an unnecessary copy).
2170 uint8_t* data = !hwaddr.hwaddr_.empty() ? const_cast<uint8_t*>(&hwaddr.hwaddr_[0])
2171 : &single_byte_data;
2172
2173 inbind[0].buffer = reinterpret_cast<char*>(data);
2174 inbind[0].buffer_length = hwaddr_length;
2175 inbind[0].length = &hwaddr_length;
2176
2177 // Get the data
2178 Lease4Collection result;
2179
2180 // Get a context
2181 MySqlLeaseContextAlloc get_context(*this);
2182 MySqlLeaseContextPtr ctx = get_context.ctx_;
2183
2184 getLeaseCollection(ctx, GET_LEASE4_HWADDR, inbind, result);
2185
2186 return (result);
2187}
2188
2190MySqlLeaseMgr::getLease4(const HWAddr& hwaddr, SubnetID subnet_id) const {
2192 .arg(subnet_id)
2193 .arg(hwaddr.toText());
2194
2195 // Set up the WHERE clause value
2196 MYSQL_BIND inbind[2];
2197 memset(inbind, 0, sizeof(inbind));
2198
2199 inbind[0].buffer_type = MYSQL_TYPE_BLOB;
2200
2201 unsigned long hwaddr_length = hwaddr.hwaddr_.size();
2202
2203 // If the data happens to be empty, we have to create a 1 byte dummy
2204 // buffer and pass it to the binding.
2205 std::vector<uint8_t> single_byte_vec(1);
2206
2207 // As "buffer" is "char*" - even though the data is being read - we need
2208 // to cast away the "const"ness as well as reinterpreting the data as
2209 // a "char*". (We could avoid the "const_cast" by copying the data to a
2210 // local variable, but as the data is only being read, this introduces
2211 // an unnecessary copy).
2212 uint8_t* data = !hwaddr.hwaddr_.empty() ? const_cast<uint8_t*>(&hwaddr.hwaddr_[0])
2213 : &single_byte_vec[0];
2214
2215 inbind[0].buffer = reinterpret_cast<char*>(data);
2216 inbind[0].buffer_length = hwaddr_length;
2217 inbind[0].length = &hwaddr_length;
2218
2219 inbind[1].buffer_type = MYSQL_TYPE_LONG;
2220 inbind[1].buffer = reinterpret_cast<char*>(&subnet_id);
2221 inbind[1].is_unsigned = MLM_TRUE;
2222
2223 // Get the data
2224 Lease4Ptr result;
2225
2226 // Get a context
2227 MySqlLeaseContextAlloc get_context(*this);
2228 MySqlLeaseContextPtr ctx = get_context.ctx_;
2229
2230 getLease(ctx, GET_LEASE4_HWADDR_SUBID, inbind, result);
2231
2232 return (result);
2233}
2234
2236MySqlLeaseMgr::getLease4(const ClientId& clientid) const {
2238 .arg(clientid.toText());
2239
2240 // Set up the WHERE clause value
2241 MYSQL_BIND inbind[1];
2242 memset(inbind, 0, sizeof(inbind));
2243
2244 inbind[0].buffer_type = MYSQL_TYPE_BLOB;
2245
2246 std::vector<uint8_t> client_data = clientid.getClientId();
2247 unsigned long client_data_length = client_data.size();
2248
2249 // If the data happens to be empty, we have to create a 1 byte dummy
2250 // buffer and pass it to the binding.
2251 if (client_data.empty()) {
2252 client_data.resize(1);
2253 }
2254
2255 inbind[0].buffer = reinterpret_cast<char*>(&client_data[0]);
2256 inbind[0].buffer_length = client_data_length;
2257 inbind[0].length = &client_data_length;
2258
2259 // Get the data
2260 Lease4Collection result;
2261
2262 // Get a context
2263 MySqlLeaseContextAlloc get_context(*this);
2264 MySqlLeaseContextPtr ctx = get_context.ctx_;
2265
2266 getLeaseCollection(ctx, GET_LEASE4_CLIENTID, inbind, result);
2267
2268 return (result);
2269}
2270
2272MySqlLeaseMgr::getLease4(const ClientId& clientid, SubnetID subnet_id) const {
2274 .arg(subnet_id)
2275 .arg(clientid.toText());
2276
2277 // Set up the WHERE clause value
2278 MYSQL_BIND inbind[2];
2279 memset(inbind, 0, sizeof(inbind));
2280
2281 inbind[0].buffer_type = MYSQL_TYPE_BLOB;
2282
2283 std::vector<uint8_t> client_data = clientid.getClientId();
2284 unsigned long client_data_length = client_data.size();
2285
2286 // If the data happens to be empty, we have to create a 1 byte dummy
2287 // buffer and pass it to the binding.
2288 if (client_data.empty()) {
2289 client_data.resize(1);
2290 }
2291
2292 inbind[0].buffer = reinterpret_cast<char*>(&client_data[0]);
2293 inbind[0].buffer_length = client_data_length;
2294 inbind[0].length = &client_data_length;
2295
2296 inbind[1].buffer_type = MYSQL_TYPE_LONG;
2297 inbind[1].buffer = reinterpret_cast<char*>(&subnet_id);
2298 inbind[1].is_unsigned = MLM_TRUE;
2299
2300 // Get the data
2301 Lease4Ptr result;
2302
2303 // Get a context
2304 MySqlLeaseContextAlloc get_context(*this);
2305 MySqlLeaseContextPtr ctx = get_context.ctx_;
2306
2307 getLease(ctx, GET_LEASE4_CLIENTID_SUBID, inbind, result);
2308
2309 return (result);
2310}
2311
2315 .arg(subnet_id);
2316
2317 // Set up the WHERE clause value
2318 MYSQL_BIND inbind[1];
2319 memset(inbind, 0, sizeof(inbind));
2320
2321 // Subnet ID
2322 inbind[0].buffer_type = MYSQL_TYPE_LONG;
2323 inbind[0].buffer = reinterpret_cast<char*>(&subnet_id);
2324 inbind[0].is_unsigned = MLM_TRUE;
2325
2326 // ... and get the data
2327 Lease4Collection result;
2328
2329 // Get a context
2330 MySqlLeaseContextAlloc get_context(*this);
2331 MySqlLeaseContextPtr ctx = get_context.ctx_;
2332
2333 getLeaseCollection(ctx, GET_LEASE4_SUBID, inbind, result);
2334
2335 return (result);
2336}
2337
2339MySqlLeaseMgr::getLeases4(const std::string& hostname) const {
2341 .arg(hostname);
2342
2343 // Set up the WHERE clause value
2344 MYSQL_BIND inbind[1];
2345 memset(inbind, 0, sizeof(inbind));
2346
2347 // Hostname
2348 inbind[0].buffer_type = MYSQL_TYPE_STRING;
2349 inbind[0].buffer = const_cast<char*>(hostname.c_str());
2350 inbind[0].buffer_length = hostname.length();
2351
2352 // ... and get the data
2353 Lease4Collection result;
2354
2355 // Get a context
2356 MySqlLeaseContextAlloc get_context(*this);
2357 MySqlLeaseContextPtr ctx = get_context.ctx_;
2358
2359 getLeaseCollection(ctx, GET_LEASE4_HOSTNAME, inbind, result);
2360
2361 return (result);
2362}
2363
2367
2368 Lease4Collection result;
2369
2370 // Get a context
2371 MySqlLeaseContextAlloc get_context(*this);
2372 MySqlLeaseContextPtr ctx = get_context.ctx_;
2373
2374 getLeaseCollection(ctx, GET_LEASE4, 0, result);
2375
2376 return (result);
2377}
2378
2380MySqlLeaseMgr::getLeases4(const IOAddress& lower_bound_address,
2381 const LeasePageSize& page_size) const {
2382 // Expecting IPv4 address.
2383 if (!lower_bound_address.isV4()) {
2384 isc_throw(InvalidAddressFamily, "expected IPv4 address while "
2385 "retrieving leases from the lease database, got "
2386 << lower_bound_address);
2387 }
2388
2390 .arg(page_size.page_size_)
2391 .arg(lower_bound_address.toText());
2392
2393 // Prepare WHERE clause
2394 MYSQL_BIND inbind[2];
2395 memset(inbind, 0, sizeof(inbind));
2396
2397 // Bind lower bound address
2398 uint32_t lb_address_data = lower_bound_address.toUint32();
2399 inbind[0].buffer_type = MYSQL_TYPE_LONG;
2400 inbind[0].buffer = reinterpret_cast<char*>(&lb_address_data);
2401 inbind[0].is_unsigned = MLM_TRUE;
2402
2403 // Bind page size value
2404 size_t* ps = const_cast<size_t*>(&page_size.page_size_);
2405 inbind[1].buffer_type = MYSQL_TYPE_LONG;
2406 inbind[1].buffer = reinterpret_cast<char*>(ps);
2407 inbind[1].is_unsigned = MLM_TRUE;
2408
2409 // Get the leases
2410 Lease4Collection result;
2411
2412 // Get a context
2413 MySqlLeaseContextAlloc get_context(*this);
2414 MySqlLeaseContextPtr ctx = get_context.ctx_;
2415
2416 getLeaseCollection(ctx, GET_LEASE4_PAGE, inbind, result);
2417
2418 return (result);
2419}
2420
2423 const IOAddress& addr) const {
2425 .arg(addr.toText())
2426 .arg(lease_type);
2427
2428 // Set up the WHERE clause value
2429 MYSQL_BIND inbind[2];
2430 memset(inbind, 0, sizeof(inbind));
2431
2432 std::string addr6 = addr.toText();
2433 unsigned long addr6_length = addr6.size();
2434
2435 // See the earlier description of the use of "const_cast" when accessing
2436 // the address for an explanation of the reason.
2437 inbind[0].buffer_type = MYSQL_TYPE_STRING;
2438 inbind[0].buffer = const_cast<char*>(addr6.c_str());
2439 inbind[0].buffer_length = addr6_length;
2440 inbind[0].length = &addr6_length;
2441
2442 // LEASE_TYPE
2443 inbind[1].buffer_type = MYSQL_TYPE_TINY;
2444 inbind[1].buffer = reinterpret_cast<char*>(&lease_type);
2445 inbind[1].is_unsigned = MLM_TRUE;
2446
2447 Lease6Ptr result;
2448
2449 // Get a context
2450 MySqlLeaseContextAlloc get_context(*this);
2451 MySqlLeaseContextPtr ctx = get_context.ctx_;
2452
2453 getLease(ctx, GET_LEASE6_ADDR, inbind, result);
2454
2455 return (result);
2456}
2457
2460 uint32_t iaid) const {
2462 .arg(iaid)
2463 .arg(duid.toText())
2464 .arg(lease_type);
2465
2466 // Set up the WHERE clause value
2467 MYSQL_BIND inbind[3];
2468 memset(inbind, 0, sizeof(inbind));
2469
2470 // In the following statement, the DUID is being read. However, the
2471 // MySQL C interface does not use "const", so the "buffer" element
2472 // is declared as "char*" instead of "const char*". To resolve this,
2473 // the "const" is discarded before the uint8_t* is cast to char*.
2474 //
2475 // Note that the const_cast could be avoided by copying the DUID to
2476 // a writable buffer and storing the address of that in the "buffer"
2477 // element. However, this introduces a copy operation (with additional
2478 // overhead) purely to get round the structures introduced by design of
2479 // the MySQL interface (which uses the area pointed to by "buffer" as
2480 // input when specifying query parameters and as output when retrieving
2481 // data). For that reason, "const_cast" has been used.
2482 const vector<uint8_t>& duid_vector = duid.getDuid();
2483 unsigned long duid_length = duid_vector.size();
2484
2485 // Make sure that the buffer has at least length of 1, even if
2486 // empty client id is passed. This is required by some of the
2487 // MySQL connectors that the buffer is set to non-null value.
2488 // Otherwise, null value would be inserted into the database,
2489 // rather than empty string.
2490 uint8_t single_byte_data = 0;
2491 uint8_t* data = !duid_vector.empty() ? const_cast<uint8_t*>(&duid_vector[0])
2492 : &single_byte_data;
2493
2494 inbind[0].buffer_type = MYSQL_TYPE_BLOB;
2495 inbind[0].buffer = reinterpret_cast<char*>(data);
2496 inbind[0].buffer_length = duid_length;
2497 inbind[0].length = &duid_length;
2498
2499 // IAID
2500 inbind[1].buffer_type = MYSQL_TYPE_LONG;
2501 inbind[1].buffer = reinterpret_cast<char*>(&iaid);
2502 inbind[1].is_unsigned = MLM_TRUE;
2503
2504 // LEASE_TYPE
2505 inbind[2].buffer_type = MYSQL_TYPE_TINY;
2506 inbind[2].buffer = reinterpret_cast<char*>(&lease_type);
2507 inbind[2].is_unsigned = MLM_TRUE;
2508
2509 // ... and get the data
2510 Lease6Collection result;
2511
2512 // Get a context
2513 MySqlLeaseContextAlloc get_context(*this);
2514 MySqlLeaseContextPtr ctx = get_context.ctx_;
2515
2516 getLeaseCollection(ctx, GET_LEASE6_DUID_IAID, inbind, result);
2517
2518 return (result);
2519}
2520
2523 uint32_t iaid, SubnetID subnet_id) const {
2525 .arg(iaid)
2526 .arg(subnet_id)
2527 .arg(duid.toText())
2528 .arg(lease_type);
2529
2530 // Set up the WHERE clause value
2531 MYSQL_BIND inbind[4];
2532 memset(inbind, 0, sizeof(inbind));
2533
2534 // See the earlier description of the use of "const_cast" when accessing
2535 // the DUID for an explanation of the reason.
2536 const vector<uint8_t>& duid_vector = duid.getDuid();
2537 unsigned long duid_length = duid_vector.size();
2538 inbind[0].buffer_type = MYSQL_TYPE_BLOB;
2539 inbind[0].buffer = reinterpret_cast<char*>(
2540 const_cast<uint8_t*>(&duid_vector[0]));
2541 inbind[0].buffer_length = duid_length;
2542 inbind[0].length = &duid_length;
2543
2544 // IAID
2545 inbind[1].buffer_type = MYSQL_TYPE_LONG;
2546 inbind[1].buffer = reinterpret_cast<char*>(&iaid);
2547 inbind[1].is_unsigned = MLM_TRUE;
2548
2549 // Subnet ID
2550 inbind[2].buffer_type = MYSQL_TYPE_LONG;
2551 inbind[2].buffer = reinterpret_cast<char*>(&subnet_id);
2552 inbind[2].is_unsigned = MLM_TRUE;
2553
2554 // LEASE_TYPE
2555 inbind[3].buffer_type = MYSQL_TYPE_TINY;
2556 inbind[3].buffer = reinterpret_cast<char*>(&lease_type);
2557 inbind[3].is_unsigned = MLM_TRUE;
2558
2559 // ... and get the data
2560 Lease6Collection result;
2561
2562 // Get a context
2563 MySqlLeaseContextAlloc get_context(*this);
2564 MySqlLeaseContextPtr ctx = get_context.ctx_;
2565
2566 getLeaseCollection(ctx, GET_LEASE6_DUID_IAID_SUBID, inbind, result);
2567
2568 return (result);
2569}
2570
2574 .arg(subnet_id);
2575
2576 // Set up the WHERE clause value
2577 MYSQL_BIND inbind[1];
2578 memset(inbind, 0, sizeof(inbind));
2579
2580 // Subnet ID
2581 inbind[0].buffer_type = MYSQL_TYPE_LONG;
2582 inbind[0].buffer = reinterpret_cast<char*>(&subnet_id);
2583 inbind[0].is_unsigned = MLM_TRUE;
2584
2585 // ... and get the data
2586 Lease6Collection result;
2587
2588 // Get a context
2589 MySqlLeaseContextAlloc get_context(*this);
2590 MySqlLeaseContextPtr ctx = get_context.ctx_;
2591
2592 getLeaseCollection(ctx, GET_LEASE6_SUBID, inbind, result);
2593
2594 return (result);
2595}
2596
2600
2601 Lease6Collection result;
2602
2603 // Get a context
2604 MySqlLeaseContextAlloc get_context(*this);
2605 MySqlLeaseContextPtr ctx = get_context.ctx_;
2606
2607 getLeaseCollection(ctx, GET_LEASE6, 0, result);
2608
2609 return (result);
2610}
2611
2615 .arg(duid.toText());
2616
2617 // Set up the WHERE clause value
2618 MYSQL_BIND inbind[1];
2619 memset(inbind, 0, sizeof(inbind));
2620
2621 const vector<uint8_t>& duid_vector = duid.getDuid();
2622 unsigned long duid_length = duid_vector.size();
2623
2624 inbind[0].buffer_type = MYSQL_TYPE_BLOB;
2625 inbind[0].buffer = reinterpret_cast<char*>(
2626 const_cast<uint8_t*>(&duid_vector[0]));
2627 inbind[0].buffer_length = duid_length;
2628 inbind[0].length = &duid_length;
2629
2630 Lease6Collection result;
2631
2632 // Get a context
2633 MySqlLeaseContextAlloc get_context(*this);
2634 MySqlLeaseContextPtr ctx = get_context.ctx_;
2635
2636 getLeaseCollection(ctx, GET_LEASE6_DUID, inbind, result);
2637
2638 return result;
2639}
2640
2642MySqlLeaseMgr::getLeases6(const std::string& hostname) const {
2644 .arg(hostname);
2645
2646 // Set up the WHERE clause value
2647 MYSQL_BIND inbind[1];
2648 memset(inbind, 0, sizeof(inbind));
2649
2650 // Hostname
2651 inbind[0].buffer_type = MYSQL_TYPE_STRING;
2652 inbind[0].buffer = const_cast<char*>(hostname.c_str());
2653 inbind[0].buffer_length = hostname.length();
2654
2655 // ... and get the data
2656 Lease6Collection result;
2657
2658 // Get a context
2659 MySqlLeaseContextAlloc get_context(*this);
2660 MySqlLeaseContextPtr ctx = get_context.ctx_;
2661
2662 getLeaseCollection(ctx, GET_LEASE6_HOSTNAME, inbind, result);
2663
2664 return (result);
2665}
2666
2668MySqlLeaseMgr::getLeases6(const IOAddress& lower_bound_address,
2669 const LeasePageSize& page_size) const {
2670 // Expecting IPv6 address.
2671 if (!lower_bound_address.isV6()) {
2672 isc_throw(InvalidAddressFamily, "expected IPv6 address while "
2673 "retrieving leases from the lease database, got "
2674 << lower_bound_address);
2675 }
2676
2678 .arg(page_size.page_size_)
2679 .arg(lower_bound_address.toText());
2680
2681 // Prepare WHERE clause
2682 MYSQL_BIND inbind[2];
2683 memset(inbind, 0, sizeof(inbind));
2684
2685 // In IPv6 we compare addresses represented as strings. The IPv6 zero address
2686 // is ::, so it is greater than any other address. In this special case, we
2687 // just use 0 for comparison which should be lower than any real IPv6 address.
2688 std::string lb_address_data = "0";
2689 if (!lower_bound_address.isV6Zero()) {
2690 lb_address_data = lower_bound_address.toText();
2691 }
2692
2693 // Bind lower bound address
2694 unsigned long lb_address_data_size = lb_address_data.size();
2695 inbind[0].buffer_type = MYSQL_TYPE_STRING;
2696 inbind[0].buffer = const_cast<char*>(lb_address_data.c_str());
2697 inbind[0].buffer_length = lb_address_data_size;
2698 inbind[0].length = &lb_address_data_size;
2699
2700 // Bind page size value
2701 size_t* ps = const_cast<size_t*>(&page_size.page_size_);
2702 inbind[1].buffer_type = MYSQL_TYPE_LONG;
2703 inbind[1].buffer = reinterpret_cast<char*>(ps);
2704 inbind[1].is_unsigned = MLM_TRUE;
2705
2706 // Get the leases
2707 Lease6Collection result;
2708
2709 // Get a context
2710 MySqlLeaseContextAlloc get_context(*this);
2711 MySqlLeaseContextPtr ctx = get_context.ctx_;
2712
2713 getLeaseCollection(ctx, GET_LEASE6_PAGE, inbind, result);
2714
2715 return (result);
2716}
2717
2718void
2720 const size_t max_leases) const {
2722 .arg(max_leases);
2723 getExpiredLeasesCommon(expired_leases, max_leases, GET_LEASE4_EXPIRE);
2724}
2725
2726void
2728 const size_t max_leases) const {
2730 .arg(max_leases);
2731 getExpiredLeasesCommon(expired_leases, max_leases, GET_LEASE6_EXPIRE);
2732}
2733
2734template<typename LeaseCollection>
2735void
2736MySqlLeaseMgr::getExpiredLeasesCommon(LeaseCollection& expired_leases,
2737 const size_t max_leases,
2738 StatementIndex statement_index) const {
2739 // Set up the WHERE clause value
2740 MYSQL_BIND inbind[3];
2741 memset(inbind, 0, sizeof(inbind));
2742
2743 // Exclude reclaimed leases.
2744 uint32_t state = static_cast<uint32_t>(Lease::STATE_EXPIRED_RECLAIMED);
2745 inbind[0].buffer_type = MYSQL_TYPE_LONG;
2746 inbind[0].buffer = reinterpret_cast<char*>(&state);
2747 inbind[0].is_unsigned = MLM_TRUE;
2748
2749 // Expiration timestamp.
2750 MYSQL_TIME expire_time;
2751 MySqlConnection::convertToDatabaseTime(time(NULL), expire_time);
2752 inbind[1].buffer_type = MYSQL_TYPE_TIMESTAMP;
2753 inbind[1].buffer = reinterpret_cast<char*>(&expire_time);
2754 inbind[1].buffer_length = sizeof(expire_time);
2755
2756 // If the number of leases is 0, we will return all leases. This is
2757 // achieved by setting the limit to a very high value.
2758 uint32_t limit = max_leases > 0 ? static_cast<uint32_t>(max_leases) :
2759 std::numeric_limits<uint32_t>::max();
2760 inbind[2].buffer_type = MYSQL_TYPE_LONG;
2761 inbind[2].buffer = reinterpret_cast<char*>(&limit);
2762 inbind[2].is_unsigned = MLM_TRUE;
2763
2764 // Get a context
2765 MySqlLeaseContextAlloc get_context(*this);
2766 MySqlLeaseContextPtr ctx = get_context.ctx_;
2767
2768 // Get the data
2769 getLeaseCollection(ctx, statement_index, inbind, expired_leases);
2770}
2771
2772// Update lease methods. These comprise common code that handles the actual
2773// update, and type-specific methods that set up the parameters for the prepared
2774// statement depending on the type of lease.
2775
2776template <typename LeasePtr>
2777void
2778MySqlLeaseMgr::updateLeaseCommon(MySqlLeaseContextPtr& ctx,
2779 StatementIndex stindex,
2780 MYSQL_BIND* bind,
2781 const LeasePtr& lease) {
2782
2783 // Bind the parameters to the statement
2784 int status = mysql_stmt_bind_param(ctx->conn_.statements_[stindex], bind);
2785 checkError(ctx, status, stindex, "unable to bind parameters");
2786
2787 // Execute
2788 status = MysqlExecuteStatement(ctx->conn_.statements_[stindex]);
2789 checkError(ctx, status, stindex, "unable to execute");
2790
2791 // See how many rows were affected. The statement should only update a
2792 // single row.
2793 int affected_rows = mysql_stmt_affected_rows(ctx->conn_.statements_[stindex]);
2794
2795 // Check success case first as it is the most likely outcome.
2796 if (affected_rows == 1) {
2797 return;
2798 }
2799
2800 // If no rows affected, lease doesn't exist.
2801 if (affected_rows == 0) {
2802 isc_throw(NoSuchLease, "unable to update lease for address " <<
2803 lease->addr_.toText() << " as it does not exist");
2804 }
2805
2806 // Should not happen - primary key constraint should only have selected
2807 // one row.
2808 isc_throw(DbOperationError, "apparently updated more than one lease "
2809 "that had the address " << lease->addr_.toText());
2810}
2811
2812void
2814 const StatementIndex stindex = UPDATE_LEASE4;
2815
2817 .arg(lease->addr_.toText());
2818
2819 // Get a context
2820 MySqlLeaseContextAlloc get_context(*this);
2821 MySqlLeaseContextPtr ctx = get_context.ctx_;
2822
2823 // Create the MYSQL_BIND array for the data being updated
2824 std::vector<MYSQL_BIND> bind = ctx->exchange4_->createBindForSend(lease);
2825
2826 // Set up the WHERE clause and append it to the MYSQL_BIND array
2827 MYSQL_BIND inbind[2];
2828 memset(inbind, 0, sizeof(inbind));
2829
2830 uint32_t addr4 = lease->addr_.toUint32();
2831 inbind[0].buffer_type = MYSQL_TYPE_LONG;
2832 inbind[0].buffer = reinterpret_cast<char*>(&addr4);
2833 inbind[0].is_unsigned = MLM_TRUE;
2834
2835 bind.push_back(inbind[0]);
2836
2837 MYSQL_TIME expire;
2838 MySqlConnection::convertToDatabaseTime(lease->current_cltt_,
2839 lease->current_valid_lft_,
2840 expire);
2841 inbind[1].buffer_type = MYSQL_TYPE_TIMESTAMP;
2842 inbind[1].buffer = reinterpret_cast<char*>(&expire);
2843 inbind[1].buffer_length = sizeof(expire);
2844
2845 bind.push_back(inbind[1]);
2846
2847 // Drop to common update code
2848 updateLeaseCommon(ctx, stindex, &bind[0], lease);
2849
2850 // Update lease current expiration time.
2851 lease->updateCurrentExpirationTime();
2852}
2853
2854void
2856 const StatementIndex stindex = UPDATE_LEASE6;
2857
2859 .arg(lease->addr_.toText())
2860 .arg(lease->type_);
2861
2862 // Get a context
2863 MySqlLeaseContextAlloc get_context(*this);
2864 MySqlLeaseContextPtr ctx = get_context.ctx_;
2865
2866 // Create the MYSQL_BIND array for the data being updated
2867 std::vector<MYSQL_BIND> bind = ctx->exchange6_->createBindForSend(lease);
2868
2869 // Set up the WHERE clause and append it to the MYSQL_BIND array
2870 MYSQL_BIND inbind[2];
2871 memset(inbind, 0, sizeof(inbind));
2872
2873 std::string addr6 = lease->addr_.toText();
2874 unsigned long addr6_length = addr6.size();
2875
2876 // See the earlier description of the use of "const_cast" when accessing
2877 // the address for an explanation of the reason.
2878 inbind[0].buffer_type = MYSQL_TYPE_STRING;
2879 inbind[0].buffer = const_cast<char*>(addr6.c_str());
2880 inbind[0].buffer_length = addr6_length;
2881 inbind[0].length = &addr6_length;
2882
2883 bind.push_back(inbind[0]);
2884
2885 MYSQL_TIME expire;
2886 MySqlConnection::convertToDatabaseTime(lease->current_cltt_,
2887 lease->current_valid_lft_,
2888 expire);
2889 inbind[1].buffer_type = MYSQL_TYPE_TIMESTAMP;
2890 inbind[1].buffer = reinterpret_cast<char*>(&expire);
2891 inbind[1].buffer_length = sizeof(expire);
2892
2893 bind.push_back(inbind[1]);
2894
2895 // Drop to common update code
2896 updateLeaseCommon(ctx, stindex, &bind[0], lease);
2897
2898 // Update lease current expiration time.
2899 lease->updateCurrentExpirationTime();
2900}
2901
2902// Delete lease methods. Similar to other groups of methods, these comprise
2903// a per-type method that sets up the relevant MYSQL_BIND array (in this
2904// case, a single method for both V4 and V6 addresses) and a common method that
2905// handles the common processing.
2906
2907uint64_t
2908MySqlLeaseMgr::deleteLeaseCommon(StatementIndex stindex,
2909 MYSQL_BIND* bind) {
2910
2911 // Get a context
2912 MySqlLeaseContextAlloc get_context(*this);
2913 MySqlLeaseContextPtr ctx = get_context.ctx_;
2914
2915 // Bind the input parameters to the statement
2916 int status = mysql_stmt_bind_param(ctx->conn_.statements_[stindex], bind);
2917 checkError(ctx, status, stindex, "unable to bind WHERE clause parameter");
2918
2919 // Execute
2920 status = MysqlExecuteStatement(ctx->conn_.statements_[stindex]);
2921 checkError(ctx, status, stindex, "unable to execute");
2922
2923 // See how many rows were affected. Note that the statement may delete
2924 // multiple rows.
2925 return (static_cast<uint64_t>(mysql_stmt_affected_rows(ctx->conn_.statements_[stindex])));
2926}
2927
2928bool
2930 const IOAddress& addr = lease->addr_;
2932 .arg(addr.toText());
2933
2934 // Set up the WHERE clause value
2935 MYSQL_BIND inbind[2];
2936 memset(inbind, 0, sizeof(inbind));
2937
2938 uint32_t addr4 = addr.toUint32();
2939
2940 inbind[0].buffer_type = MYSQL_TYPE_LONG;
2941 inbind[0].buffer = reinterpret_cast<char*>(&addr4);
2942 inbind[0].is_unsigned = MLM_TRUE;
2943
2944 MYSQL_TIME expire;
2945 MySqlConnection::convertToDatabaseTime(lease->current_cltt_,
2946 lease->current_valid_lft_,
2947 expire);
2948 inbind[1].buffer_type = MYSQL_TYPE_TIMESTAMP;
2949 inbind[1].buffer = reinterpret_cast<char*>(&expire);
2950 inbind[1].buffer_length = sizeof(expire);
2951
2952 auto affected_rows = deleteLeaseCommon(DELETE_LEASE4, inbind);
2953
2954 // Check success case first as it is the most likely outcome.
2955 if (affected_rows == 1) {
2956 return (true);
2957 }
2958
2959 // If no rows affected, lease doesn't exist.
2960 if (affected_rows == 0) {
2961 return (false);
2962 }
2963
2964 // Should not happen - primary key constraint should only have selected
2965 // one row.
2966 isc_throw(DbOperationError, "apparently deleted more than one lease "
2967 "that had the address " << lease->addr_.toText());
2968}
2969
2970bool
2972 const IOAddress& addr = lease->addr_;
2975 .arg(addr.toText());
2976
2977 // Set up the WHERE clause value
2978 MYSQL_BIND inbind[2];
2979 memset(inbind, 0, sizeof(inbind));
2980
2981 std::string addr6 = addr.toText();
2982 unsigned long addr6_length = addr6.size();
2983
2984 // See the earlier description of the use of "const_cast" when accessing
2985 // the address for an explanation of the reason.
2986 inbind[0].buffer_type = MYSQL_TYPE_STRING;
2987 inbind[0].buffer = const_cast<char*>(addr6.c_str());
2988 inbind[0].buffer_length = addr6_length;
2989 inbind[0].length = &addr6_length;
2990
2991 MYSQL_TIME expire;
2992 MySqlConnection::convertToDatabaseTime(lease->current_cltt_,
2993 lease->current_valid_lft_,
2994 expire);
2995 inbind[1].buffer_type = MYSQL_TYPE_TIMESTAMP;
2996 inbind[1].buffer = reinterpret_cast<char*>(&expire);
2997 inbind[1].buffer_length = sizeof(expire);
2998
2999 auto affected_rows = deleteLeaseCommon(DELETE_LEASE6, inbind);
3000
3001 // Check success case first as it is the most likely outcome.
3002 if (affected_rows == 1) {
3003 return (true);
3004 }
3005
3006 // If no rows affected, lease doesn't exist.
3007 if (affected_rows == 0) {
3008 return (false);
3009 }
3010
3011 // Should not happen - primary key constraint should only have selected
3012 // one row.
3013 isc_throw(DbOperationError, "apparently deleted more than one lease "
3014 "that had the address " << lease->addr_.toText());
3015}
3016
3017uint64_t
3020 .arg(secs);
3021 return (deleteExpiredReclaimedLeasesCommon(secs, DELETE_LEASE4_STATE_EXPIRED));
3022}
3023
3024uint64_t
3027 .arg(secs);
3028 return (deleteExpiredReclaimedLeasesCommon(secs, DELETE_LEASE6_STATE_EXPIRED));
3029}
3030
3031uint64_t
3032MySqlLeaseMgr::deleteExpiredReclaimedLeasesCommon(const uint32_t secs,
3033 StatementIndex statement_index) {
3034 // Set up the WHERE clause value
3035 MYSQL_BIND inbind[2];
3036 memset(inbind, 0, sizeof(inbind));
3037
3038 // State is reclaimed.
3039 uint32_t state = static_cast<uint32_t>(Lease::STATE_EXPIRED_RECLAIMED);
3040 inbind[0].buffer_type = MYSQL_TYPE_LONG;
3041 inbind[0].buffer = reinterpret_cast<char*>(&state);
3042 inbind[0].is_unsigned = MLM_TRUE;
3043
3044 // Expiration timestamp.
3045 MYSQL_TIME expire_time;
3046 MySqlConnection::convertToDatabaseTime(time(NULL) - static_cast<time_t>(secs), expire_time);
3047 inbind[1].buffer_type = MYSQL_TYPE_TIMESTAMP;
3048 inbind[1].buffer = reinterpret_cast<char*>(&expire_time);
3049 inbind[1].buffer_length = sizeof(expire_time);
3050
3051 // Get the number of deleted leases and log it.
3052 uint64_t deleted_leases = deleteLeaseCommon(statement_index, inbind);
3054 .arg(deleted_leases);
3055
3056 return (deleted_leases);
3057}
3058
3061 // Get a context
3062 MySqlLeaseContextAlloc get_context(*this);
3063 MySqlLeaseContextPtr ctx = get_context.ctx_;
3064
3065 LeaseStatsQueryPtr query(new MySqlLeaseStatsQuery(ctx->conn_,
3067 false));
3068 query->start();
3069 return(query);
3070}
3071
3074 // Get a context
3075 MySqlLeaseContextAlloc get_context(*this);
3076 MySqlLeaseContextPtr ctx = get_context.ctx_;
3077
3078 LeaseStatsQueryPtr query(new MySqlLeaseStatsQuery(ctx->conn_,
3080 false,
3081 subnet_id));
3082 query->start();
3083 return(query);
3084}
3085
3088 const SubnetID& last_subnet_id) {
3089 // Get a context
3090 MySqlLeaseContextAlloc get_context(*this);
3091 MySqlLeaseContextPtr ctx = get_context.ctx_;
3092
3093 LeaseStatsQueryPtr query(new MySqlLeaseStatsQuery(ctx->conn_,
3095 false,
3096 first_subnet_id,
3097 last_subnet_id));
3098 query->start();
3099 return(query);
3100}
3101
3104 // Get a context
3105 MySqlLeaseContextAlloc get_context(*this);
3106 MySqlLeaseContextPtr ctx = get_context.ctx_;
3107
3108 LeaseStatsQueryPtr query(new MySqlLeaseStatsQuery(ctx->conn_,
3110 true));
3111 query->start();
3112 return(query);
3113}
3114
3117 // Get a context
3118 MySqlLeaseContextAlloc get_context(*this);
3119 MySqlLeaseContextPtr ctx = get_context.ctx_;
3120
3121 LeaseStatsQueryPtr query(new MySqlLeaseStatsQuery(ctx->conn_,
3123 true,
3124 subnet_id));
3125 query->start();
3126 return(query);
3127}
3128
3131 const SubnetID& last_subnet_id) {
3132 // Get a context
3133 MySqlLeaseContextAlloc get_context(*this);
3134 MySqlLeaseContextPtr ctx = get_context.ctx_;
3135
3136 LeaseStatsQueryPtr query(new MySqlLeaseStatsQuery(ctx->conn_,
3138 true,
3139 first_subnet_id,
3140 last_subnet_id));
3141 query->start();
3142 return(query);
3143}
3144
3145size_t
3147 isc_throw(NotImplemented, "wipeLeases4 is not implemented for MySQL backend");
3148}
3149
3150size_t
3152 isc_throw(NotImplemented, "wipeLeases6 is not implemented for MySQL backend");
3153}
3154
3155// Miscellaneous database methods.
3156
3157std::string
3159 // Get a context
3160 MySqlLeaseContextAlloc get_context(*this);
3161 MySqlLeaseContextPtr ctx = get_context.ctx_;
3162
3163 std::string name = "";
3164 try {
3165 name = ctx->conn_.getParameter("name");
3166 } catch (...) {
3167 // Return an empty name
3168 }
3169 return (name);
3170}
3171
3172std::string
3174 return (std::string("MySQL Database"));
3175}
3176
3177std::pair<uint32_t, uint32_t>
3180
3181 return (MySqlConnection::getVersion(parameters_));
3182}
3183
3184void
3187}
3188
3189void
3192}
3193
3194void
3195MySqlLeaseMgr::checkError(MySqlLeaseContextPtr& ctx,
3196 int status, StatementIndex index,
3197 const char* what) const {
3198 ctx->conn_.checkError(status, index, what);
3199}
3200
3201} // namespace dhcp
3202} // namespace isc
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
A generic exception that is thrown when a function is not implemented.
A generic exception that is thrown when an unexpected error condition occurs.
Data is truncated.
Definition: db_exceptions.h:35
static bool invokeDbLostCallback(const ReconnectCtlPtr &db_reconnect_ctl)
Invokes the connection's lost connectivity callback.
static bool invokeDbFailedCallback(const ReconnectCtlPtr &db_reconnect_ctl)
Invokes the connection's restore failed connectivity callback.
std::map< std::string, std::string > ParameterMap
Database configuration parameter map.
static bool invokeDbRecoveredCallback(const ReconnectCtlPtr &db_reconnect_ctl)
Invokes the connection's restored connectivity callback.
Exception thrown on failure to open database.
Exception thrown on failure to execute a database function.
Invalid address family used as input to Lease Manager.
Definition: db_exceptions.h:71
Multiple lease records found where one expected.
Definition: db_exceptions.h:28
Common MySQL Connector Pool.
std::vector< MYSQL_STMT * > statements_
Prepared statements.
static void convertToDatabaseTime(const time_t input_time, MYSQL_TIME &output_time)
Convert time_t value to database time.
static void convertFromDatabaseTime(const MYSQL_TIME &expire, uint32_t valid_lifetime, time_t &cltt)
Convert Database Time to Lease Times.
static std::pair< uint32_t, uint32_t > getVersion(const ParameterMap &parameters)
Get the schema version.
void checkError(const int status, const StatementIndex &index, const char *what)
Check Error and Throw Exception.
Fetch and Release MySQL Results.
static CfgMgr & instance()
returns a single instance of Configuration Manager
Definition: cfgmgr.cc:25
SrvConfigPtr getCurrentCfg()
Returns a pointer to the current configuration.
Definition: cfgmgr.cc:161
Holds Client identifier or client IPv4 address.
Definition: duid.h:111
static const size_t MAX_CLIENT_ID_LEN
Maximum size of a client ID.
Definition: duid.h:128
const std::vector< uint8_t > & getClientId() const
Returns reference to the client-id data.
Definition: duid.cc:117
std::string toText() const
Returns textual representation of a DUID (e.g. 00:01:02:03:ff)
Definition: duid.cc:122
Holds DUID (DHCPv6 Unique Identifier)
Definition: duid.h:27
std::string toText() const
Returns textual representation of a DUID (e.g. 00:01:02:03:ff)
Definition: duid.cc:75
static const size_t MAX_DUID_LEN
maximum duid size As defined in RFC 8415, section 11.1
Definition: duid.h:31
const std::vector< uint8_t > & getDuid() const
Returns a const reference to the actual DUID value.
Definition: duid.cc:46
static void create(const std::string &dbaccess)
Create an instance of a lease manager.
static void destroy()
Destroy lease manager.
static isc::asiolink::IOServicePtr & getIOService()
Returns pointer to the IO service.
Definition: lease_mgr.h:758
Wraps value holding size of the page with leases.
Definition: lease_mgr.h:43
const size_t page_size_
Holds page size.
Definition: lease_mgr.h:53
Base class for fulfilling a statistical lease data query.
Definition: lease_mgr.h:128
SubnetID first_subnet_id_
First (or only) subnet_id in the selection criteria.
Definition: lease_mgr.h:192
SelectMode getSelectMode() const
Returns the selection criteria mode The value returned is based upon the constructor variant used and...
Definition: lease_mgr.h:190
SubnetID last_subnet_id_
Last subnet_id in the selection criteria when a range is given.
Definition: lease_mgr.h:199
Exchange MySQL and Lease4 Data.
std::vector< MYSQL_BIND > createBindForReceive()
Create BIND array to receive data.
std::vector< MYSQL_BIND > createBindForSend(const Lease4Ptr &lease)
Create MYSQL_BIND objects for Lease4 Pointer.
std::string getErrorColumns()
Return columns in error.
Lease4Ptr getLeaseData()
Copy Received Data into Lease4 Object.
Exchange MySQL and Lease6 Data.
std::vector< MYSQL_BIND > createBindForSend(const Lease6Ptr &lease)
Create MYSQL_BIND objects for Lease6 Pointer.
std::string getErrorColumns()
Return columns in error.
Lease6Ptr getLeaseData()
Copy Received Data into Lease6 Object.
std::vector< MYSQL_BIND > createBindForReceive()
Create BIND array to receive data.
MySQL Lease Context Pool.
MySQL Lease Context.
MySqlLeaseContext(const db::DatabaseConnection::ParameterMap &parameters, db::IOServiceAccessorPtr io_service_accessor, db::DbCallback db_reconnect_callback)
Constructor.
Common MySQL and Lease Data Methods.
static std::string getColumnsInError(my_bool *error, std::string *names, size_t count)
Return columns in error.
static void setErrorIndicators(MYSQL_BIND *bind, my_bool *error, size_t count)
Set error indicators.
MySQL Lease Manager.
virtual std::string getName() const
Returns backend name.
virtual void rollback()
Rollback Transactions.
virtual size_t wipeLeases4(const SubnetID &subnet_id)
Removes specified IPv4 leases.
static std::string getDBVersion()
Local version of getDBVersion() class method.
virtual std::string getDescription() const
Returns description of the backend.
virtual void commit()
Commit Transactions.
virtual void getExpiredLeases6(Lease6Collection &expired_leases, const size_t max_leases) const
Returns a collection of expired DHCPv6 leases.
virtual std::pair< uint32_t, uint32_t > getVersion() const
Returns backend version.
virtual Lease6Collection getLeases6() const
Returns all IPv6 leases.
virtual LeaseStatsQueryPtr startSubnetLeaseStatsQuery6(const SubnetID &subnet_id)
Creates and runs the IPv6 lease stats query for a single subnet.
virtual bool addLease(const Lease4Ptr &lease)
Adds an IPv4 lease.
virtual size_t wipeLeases6(const SubnetID &subnet_id)
Removed specified IPv6 leases.
MySqlLeaseContextPtr createContext() const
Create a new context.
virtual Lease6Ptr getLease6(Lease::Type type, const isc::asiolink::IOAddress &addr) const
Returns existing IPv6 lease for a given IPv6 address.
virtual bool deleteLease(const Lease4Ptr &lease)
Deletes an IPv4 lease.
virtual uint64_t deleteExpiredReclaimedLeases6(const uint32_t secs)
Deletes all expired-reclaimed DHCPv6 leases.
virtual void updateLease6(const Lease6Ptr &lease6)
Updates IPv6 lease.
virtual LeaseStatsQueryPtr startSubnetLeaseStatsQuery4(const SubnetID &subnet_id)
Creates and runs the IPv4 lease stats query for a single subnet.
virtual LeaseStatsQueryPtr startSubnetRangeLeaseStatsQuery6(const SubnetID &first_subnet_id, const SubnetID &last_subnet_id)
Creates and runs the IPv6 lease stats query for a single subnet.
MySqlLeaseMgr(const db::DatabaseConnection::ParameterMap &parameters)
Constructor.
virtual LeaseStatsQueryPtr startLeaseStatsQuery4()
Creates and runs the IPv4 lease stats query.
virtual void updateLease4(const Lease4Ptr &lease4)
Updates IPv4 lease.
virtual uint64_t deleteExpiredReclaimedLeases4(const uint32_t secs)
Deletes all expired-reclaimed DHCPv4 leases.
StatementIndex
Statement Tags.
virtual void getExpiredLeases4(Lease4Collection &expired_leases, const size_t max_leases) const
Returns a collection of expired DHCPv4 leases.
virtual LeaseStatsQueryPtr startSubnetRangeLeaseStatsQuery4(const SubnetID &first_subnet_id, const SubnetID &last_subnet_id)
Creates and runs the IPv4 lease stats query for a single subnet.
virtual LeaseStatsQueryPtr startLeaseStatsQuery6()
Creates and runs the IPv6 lease stats query.
virtual Lease4Collection getLeases4() const
Returns all IPv4 leases.
virtual Lease4Ptr getLease4(const isc::asiolink::IOAddress &addr) const
Returns an IPv4 lease for specified IPv4 address.
virtual ~MySqlLeaseMgr()
Destructor (closes database)
static bool dbReconnect(db::ReconnectCtlPtr db_reconnect_ctl)
Attempts to reconnect the server to the lease DB backend manager.
MySql derivation of the statistical lease data query.
void start()
Creates the IPv4 lease statistical data result set.
MySqlLeaseStatsQuery(MySqlConnection &conn, const size_t statement_index, const bool fetch_type, const SubnetID &first_subnet_id, const SubnetID &last_subnet_id)
Constructor to query for the stats for a range of subnets.
MySqlLeaseStatsQuery(MySqlConnection &conn, const size_t statement_index, const bool fetch_type, const SubnetID &subnet_id)
Constructor to query for a single subnet's stats.
virtual ~MySqlLeaseStatsQuery()
Destructor.
bool getNextRow(LeaseStatsRow &row)
Fetches the next row in the result set.
MySqlLeaseStatsQuery(MySqlConnection &conn, const size_t statement_index, const bool fetch_type)
Constructor to query for all subnets' stats.
Attempt to update lease that was not there.
static const TimerMgrPtr & instance()
Returns pointer to the sole instance of the TimerMgr.
Definition: timer_mgr.cc:449
RAII class creating a critical section.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
Definition: macros.h:32
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
Definition: macros.h:20
#define LOG_WARN(LOGGER, MESSAGE)
Macro to conveniently test warn output and log it.
Definition: macros.h:26
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition: macros.h:14
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:27
const my_bool MLM_FALSE
MySQL false value.
std::function< bool(ReconnectCtlPtr db_reconnect_ctl)> DbCallback
Defines a callback prototype for propagating events upward.
const uint32_t MYSQL_SCHEMA_VERSION_MAJOR
boost::shared_ptr< IOServiceAccessor > IOServiceAccessorPtr
Pointer to an instance of IOServiceAccessor.
@ error
Definition: db_log.h:118
const uint32_t MYSQL_SCHEMA_VERSION_MINOR
const my_bool MLM_TRUE
MySQL true value.
bool my_bool
my_bool type in MySQL 8.x.
const int MLM_MYSQL_FETCH_SUCCESS
check for bool size
std::function< isc::asiolink::IOServicePtr()> IOServiceAccessor
Function which returns the IOService that can be used to recover the connection.
int MysqlExecuteStatement(MYSQL_STMT *stmt)
Execute a prepared statement.
boost::shared_ptr< ReconnectCtl > ReconnectCtlPtr
Pointer to an instance of ReconnectCtl.
const isc::log::MessageID DHCPSRV_MYSQL_GET_HOSTNAME4
isc::log::Logger dhcpsrv_logger("dhcpsrv")
DHCP server library Logger.
Definition: dhcpsrv_log.h:56
const isc::log::MessageID DHCPSRV_MYSQL_GET_EXPIRED6
const isc::log::MessageID DHCPSRV_MYSQL_ADD_ADDR4
const isc::log::MessageID DHCPSRV_MYSQL_COMMIT
const isc::log::MessageID DHCPSRV_MYSQL_DELETE_EXPIRED_RECLAIMED6
const isc::log::MessageID DHCPSRV_MYSQL_NEGATIVE_LEASES_STAT
const isc::log::MessageID DHCPSRV_MYSQL_GET_IAID_DUID
const isc::log::MessageID DHCPSRV_MYSQL_GET_PAGE4
const isc::log::MessageID DHCPSRV_MYSQL_GET_CLIENTID
const isc::log::MessageID DHCPSRV_MYSQL_GET4
boost::shared_ptr< CfgDbAccess > CfgDbAccessPtr
A pointer to the CfgDbAccess.
boost::shared_ptr< DUID > DuidPtr
Definition: duid.h:20
const isc::log::MessageID DHCPSRV_MYSQL_DELETE_ADDR
boost::shared_ptr< Lease6 > Lease6Ptr
Pointer to a Lease6 structure.
Definition: lease.h:492
std::vector< Lease6Ptr > Lease6Collection
A collection of IPv6 leases.
Definition: lease.h:640
boost::shared_ptr< LeaseStatsQuery > LeaseStatsQueryPtr
Defines a pointer to a LeaseStatsQuery.
Definition: lease_mgr.h:207
const isc::log::MessageID DHCPSRV_MYSQL_LEASE_DB_RECONNECT_ATTEMPT_FAILED
const isc::log::MessageID DHCPSRV_MYSQL_GET_ADDR4
const isc::log::MessageID DHCPSRV_MYSQL_GET_IAID_SUBID_DUID
const isc::log::MessageID DHCPSRV_MYSQL_UPDATE_ADDR6
boost::shared_ptr< HWAddr > HWAddrPtr
Shared pointer to a hardware address structure.
Definition: hwaddr.h:154
const int DHCPSRV_DBG_TRACE_DETAIL
Additional information.
Definition: dhcpsrv_log.h:38
const isc::log::MessageID DHCPSRV_MYSQL_GET_SUBID6
const isc::log::MessageID DHCPSRV_MYSQL_GET_PAGE6
const isc::log::MessageID DHCPSRV_MYSQL_GET_EXPIRED4
const isc::log::MessageID DHCPSRV_MYSQL_UPDATE_ADDR4
const isc::log::MessageID DHCPSRV_MYSQL_GET_HWADDR
uint32_t SubnetID
Unique identifier for a subnet (both v4 and v6)
Definition: lease.h:24
boost::shared_ptr< Lease > LeasePtr
Pointer to the lease object.
Definition: lease.h:26
const isc::log::MessageID DHCPSRV_MYSQL_ADD_ADDR6
const isc::log::MessageID DHCPSRV_MYSQL_GET_HOSTNAME6
const isc::log::MessageID DHCPSRV_MYSQL_GET_VERSION
const isc::log::MessageID DHCPSRV_MYSQL_LEASE_DB_RECONNECT_ATTEMPT_SCHEDULE
const isc::log::MessageID DHCPSRV_MYSQL_GET_SUBID4
const isc::log::MessageID DHCPSRV_MYSQL_GET6
const size_t USER_CONTEXT_MAX_LEN
Maximum length of user context.
Definition: host.h:54
const isc::log::MessageID DHCPSRV_MYSQL_LEASE_DB_RECONNECT_FAILED
const isc::log::MessageID DHCPSRV_MYSQL_GET_SUBID_CLIENTID
const isc::log::MessageID DHCPSRV_MYSQL_DELETE_EXPIRED_RECLAIMED4
std::vector< Lease4Ptr > Lease4Collection
A collection of IPv4 leases.
Definition: lease.h:487
const isc::log::MessageID DHCPSRV_MYSQL_ROLLBACK
@ HTYPE_ETHER
Ethernet 10Mbps.
Definition: dhcp4.h:56
boost::shared_ptr< Lease4 > Lease4Ptr
Pointer to a Lease4 structure.
Definition: lease.h:283
boost::shared_ptr< MySqlLeaseContext > MySqlLeaseContextPtr
Type of pointers to contexts.
const isc::log::MessageID DHCPSRV_MYSQL_GET_ADDR6
const isc::log::MessageID DHCPSRV_MYSQL_GET_SUBID_HWADDR
const isc::log::MessageID DHCPSRV_MYSQL_DELETED_EXPIRED_RECLAIMED
const isc::log::MessageID DHCPSRV_MYSQL_GET_DUID
Definition: edns.h:19
Defines the logger used by the top-level component of kea-lfc.
Hardware type that represents information from DHCPv4 packet.
Definition: hwaddr.h:20
static const size_t MAX_HWADDR_LEN
Maximum size of a hardware address.
Definition: hwaddr.h:27
std::vector< uint8_t > hwaddr_
Definition: hwaddr.h:98
std::string toText(bool include_htype=true) const
Returns textual representation of a hardware address (e.g.
Definition: hwaddr.cc:51
Contains a single row of lease statistical data.
Definition: lease_mgr.h:61
int64_t state_count_
state_count The count of leases in the lease state
Definition: lease_mgr.h:120
uint32_t lease_state_
The lease_state to which the count applies.
Definition: lease_mgr.h:118
SubnetID subnet_id_
The subnet ID to which this data applies.
Definition: lease_mgr.h:114
Lease::Type lease_type_
The lease_type to which the count applies.
Definition: lease_mgr.h:116
static const uint32_t INFINITY_LFT
Infinity (means static, i.e. never expire)
Definition: lease.h:38
static const uint32_t STATE_EXPIRED_RECLAIMED
Expired and reclaimed lease.
Definition: lease.h:79
Type
Type of lease or pool.
Definition: lease.h:50
@ TYPE_TA
the lease contains temporary IPv6 address
Definition: lease.h:52
@ TYPE_PD
the lease contains IPv6 prefix (for prefix delegation)
Definition: lease.h:53
@ TYPE_NA
the lease contains non-temporary IPv6 address
Definition: lease.h:51